Liking cljdoc? Tell your friends :D

com.blockether.vis.ext.channel-tui.magit

Magit-style PORCELAIN layer for the TUI — the pure, testable half of the C-x g status buffer. Everything runs over the native git CLI via internal.git/run-git; nothing here touches a terminal.

Three surfaces:

  • status-model — one snapshot of the repo: head/upstream facts plus the magit sections (untracked / unstaged / staged / unmerged / stashes / unpushed / unpulled / recent commits).
  • actions — stage-file!, unstage-file!, discard-file!, commit!, push!, pull!, fetch!, branch and stash verbs. Each returns {:ok? bool :msg str} so the dialog can echo success/failure verbatim.
  • status-rows — PURE projection of a model (+ the expanded-diff set) into renderable row maps; the dialog only paints and moves a cursor over what this returns.

Keeping the model/actions/rows split pure means the whole magit feature is exercisable in tests against a throw-away repo, with zero lanterna.

Magit-style PORCELAIN layer for the TUI — the pure, testable half of the
C-x g status buffer. Everything runs over the native `git` CLI via
`internal.git/run-git`; nothing here touches a terminal.

Three surfaces:

- `status-model`   — one snapshot of the repo: head/upstream facts plus the
                     magit sections (untracked / unstaged / staged /
                     unmerged / stashes / unpushed / unpulled / recent
                     commits).
- actions          — `stage-file!`, `unstage-file!`, `discard-file!`,
                     `commit!`, `push!`, `pull!`, `fetch!`, branch and
                     stash verbs. Each returns `{:ok? bool :msg str}` so
                     the dialog can echo success/failure verbatim.
- `status-rows`    — PURE projection of a model (+ the expanded-diff set)
                     into renderable row maps; the dialog only paints and
                     moves a cursor over what this returns.

Keeping the model/actions/rows split pure means the whole magit feature is
exercisable in tests against a throw-away repo, with zero lanterna.
raw docstring

catalog-entriesclj

(catalog-entries)

The workspace.filesystem catalog of the MERGED configuration — the global ~/.vis/config.yml, the project's own vis.yml and its .vis/config.yml overlay — reduced to the entries that mount on THIS host (when / optional). load-config-raw is memoized against the config files' mtimes, so an edited vis.yml reaches the next status buffer without a /reload. Never throws: an unreadable or invalid config simply declares nothing.

The `workspace.filesystem` catalog of the MERGED configuration — the global
`~/.vis/config.yml`, the project's own `vis.yml` and its `.vis/config.yml`
overlay — reduced to the entries that mount on THIS host (`when` / `optional`).
`load-config-raw` is memoized against the config files' mtimes, so an edited
`vis.yml` reaches the next status buffer without a `/reload`. Never throws: an
unreadable or invalid config simply declares nothing.
sourceraw docstring

checkout-branch!clj

(checkout-branch! root branch)
source

commit!clj

(commit! root message {:keys [amend? no-verify?]})

Refuses an empty message and — like magit's Nothing staged guard — a non-amend commit over a clean index (a bare git commit failure would echo a whole status dump). The index guard only applies when HEAD resolves: diff --cached --quiet reports clean on an unborn branch even with staged files.

opts: :amend? adds --amend, :no-verify? adds --no-verify so the pre-commit / commit-msg githooks are skipped (magit's commit transient -n Disable hooks). :no-verify? never relaxes vis' OWN :git/commit authorization boundary — it only silences git's hooks.

Refuses an empty message and — like magit's `Nothing staged` guard — a
non-amend commit over a clean index (a bare `git commit` failure would echo
a whole status dump). The index guard only applies when HEAD resolves:
`diff --cached --quiet` reports clean on an unborn branch even with staged
files.

`opts`: :amend? adds `--amend`, :no-verify? adds `--no-verify` so the
pre-commit / commit-msg githooks are skipped (magit's commit transient
`-n Disable hooks`). :no-verify? never relaxes vis' OWN `:git/commit`
authorization boundary — it only silences git's hooks.
sourceraw docstring

commit-diff-linesclj

(commit-diff-lines root {:keys [sha]})

Diff body for one commit row, as plain lines (for the TAB fold): the patch git show produces for sha, kept from the first diff --git header down so every file the commit touched is named.

Diff body for one commit row, as plain lines (for the TAB fold): the patch
`git show` produces for `sha`, kept from the first `diff --git` header down so
every file the commit touched is named.
sourceraw docstring

configured-rootsclj

(configured-roots ws)
(configured-roots ws entries)

Repo entries for the repositories DECLARED in the workspace.filesystem catalog of vis.yml — the sibling checkouts a project binds into the session (- id: spel / path: ~/spel). They live OUTSIDE the project tree, so nested-roots can never discover them: the catalog is the only place they are named. Each is labelled by its catalog id, the same name vis doctor and jail.filesystem.allow use.

Two declared roots are skipped. A read-only one: the status buffer stages, commits and pushes, so it is an ACTION surface and a reference tree is not meant to be acted on. And one that holds no .git, which is every cache the catalog grants.

Draft isolation is obeyed exactly as the tool layer obeys it. In a DRAFTED session a not-allowed root is withheld entirely, and a copy-only / copy-and-apply root shows the private clone minted for that draft — never the real root — or is withheld when no clone was minted. A verb can therefore never write through a root the draft promised to isolate.

Repo entries for the repositories DECLARED in the `workspace.filesystem`
catalog of `vis.yml` — the sibling checkouts a project binds into the session
(`- id: spel` / `path: ~/spel`). They live OUTSIDE the project tree, so
`nested-roots` can never discover them: the catalog is the only place they are
named. Each is labelled by its catalog `id`, the same name `vis doctor` and
`jail.filesystem.allow` use.

Two declared roots are skipped. A `read-only` one: the status buffer stages,
commits and pushes, so it is an ACTION surface and a reference tree is not
meant to be acted on. And one that holds no `.git`, which is every cache the
catalog grants.

Draft isolation is obeyed exactly as the tool layer obeys it. In a DRAFTED
session a `not-allowed` root is withheld entirely, and a `copy-only` /
`copy-and-apply` root shows the private clone minted for that draft — never
the real root — or is withheld when no clone was minted. A verb can therefore
never write through a root the draft promised to isolate.
sourceraw docstring

create-branch!clj

(create-branch! root name)

Create AND check out name (magit's b c).

Create AND check out `name` (magit's `b c`).
sourceraw docstring

current-branchclj

(current-branch root)

Short name of the current branch (main), or nil on a detached/unborn HEAD.

Short name of the current branch (`main`), or nil on a detached/unborn HEAD.
sourceraw docstring

delete-branch!clj

(delete-branch! root name {:keys [force?]})
source

discard-file!clj

(discard-file! root {:keys [path area]})

Magit's k: throw the change away.

  • untracked file → delete it (git clean -f)
  • UNSTAGED change → restore the INDEX version in the worktree only (git checkout -- path) — the staged half of the same file survives, exactly like magit
  • staged change in HEAD → restore the HEAD version in index AND worktree
  • added, not in HEAD → unstage only (the file survives as untracked — never silently delete content git has never stored).
Magit's `k`: throw the change away.
- untracked file        → delete it (`git clean -f`)
- UNSTAGED change       → restore the INDEX version in the worktree only
                          (`git checkout -- path`) — the staged half of the
                          same file survives, exactly like magit
- staged change in HEAD → restore the HEAD version in index AND worktree
- added, not in HEAD    → unstage only (the file survives as untracked —
  never silently delete content git has never stored).
sourceraw docstring

fetch!clj

(fetch! root)
source

file-diff-linesclj

(file-diff-lines root {:keys [path area]})

Diff body for one file row, as plain lines (for the TAB fold). area picks the side: :staged → diff --cached, :unstaged/:unmerged → diff, :untracked → the file's own content rendered as additions.

Diff body for one file row, as plain lines (for the TAB fold).
`area` picks the side: :staged → `diff --cached`, :unstaged/:unmerged →
`diff`, :untracked → the file's own content rendered as additions.
sourceraw docstring

first-selectableclj

(first-selectable rows idx)

Index of the first selectable row at-or-after idx (wrapping search both directions handled by the caller); nil when nothing is selectable.

Index of the first selectable row at-or-after `idx` (wrapping search both
directions handled by the caller); nil when nothing is selectable.
sourceraw docstring

gerrit-push!clj

(gerrit-push! root {:keys [remote branch topic dry-run? no-verify?]})

Push HEAD to Gerrit for review (refs/for/<branch>) — a regular push, just carrying an optional Gerrit topic. opts: :remote :branch :topic :dry-run? :no-verify?. remote/branch default to the detected Gerrit remote and upstream branch.

Push HEAD to Gerrit for review (`refs/for/<branch>`) — a regular push, just
carrying an optional Gerrit topic. `opts`: :remote :branch :topic :dry-run?
:no-verify?. `remote`/`branch` default to the detected Gerrit remote and
upstream branch.
sourceraw docstring

gerrit-remoteclj

(gerrit-remote root)

Name of the remote that talks to a Gerrit server, or nil. Prefers an explicit gerrit remote, then any remote whose URL smells like Gerrit, then falls back to the first remote when a .gitreview file is present.

Name of the remote that talks to a Gerrit server, or nil. Prefers an explicit
`gerrit` remote, then any remote whose URL smells like Gerrit, then falls back
to the first remote when a `.gitreview` file is present.
sourceraw docstring

gerrit-target-branchclj

(gerrit-target-branch root)

Branch a Gerrit review targets: the upstream branch (minus its remote), else the current branch, else master.

Branch a Gerrit review targets: the upstream branch (minus its remote), else
the current branch, else `master`.
sourceraw docstring

gerrit?clj

(gerrit? root)

True when this repo appears to target a Gerrit server.

True when this repo appears to target a Gerrit server.
sourceraw docstring

head-rowsclj

(head-rows {:keys [branch detached? head head-subject upstream? upstream ahead
                   behind]})

The Head: / Merge: preamble of the status buffer.

The `Head:` / `Merge:` preamble of the status buffer.
sourceraw docstring

head-subjectclj

(head-subject root)

Subject line of HEAD's commit, or nil on an unborn branch.

Subject line of HEAD's commit, or nil on an unborn branch.
sourceraw docstring

last-commit-messageclj

(last-commit-message root)

Full message of HEAD's commit (for amend pre-fill), or nil.

Full message of HEAD's commit (for amend pre-fill), or nil.
sourceraw docstring

load-reposclj

(load-repos repo-entries)

Attach a fresh :model snapshot to every repo entry — one status-model read per root — then DROP every root that is not a git repository (:model nil). A non-repo root has nothing to show, so it never earns a header in the multi-root buffer. The refresh path of a multi-root buffer.

The reads run in PARALLEL (pmap, order preserved): every root costs a handful of git subprocesses, and a dozen roots refreshed one after another is what would make the buffer feel slow after each verb.

Fallback: when NOT ONE root is a git repository the first entry is kept (with its nil :model) so a repo-less session still renders the single-root Not a git repository empty state instead of a blank buffer.

Attach a fresh `:model` snapshot to every repo entry — one `status-model`
read per root — then DROP every root that is not a git repository (`:model`
nil). A non-repo root has nothing to show, so it never earns a header in the
multi-root buffer. The refresh path of a multi-root buffer.

The reads run in PARALLEL (`pmap`, order preserved): every root costs a
handful of git subprocesses, and a dozen roots refreshed one after another is
what would make the buffer feel slow after each verb.

Fallback: when NOT ONE root is a git repository the first entry is kept (with
its nil `:model`) so a repo-less session still renders the single-root
`Not a git repository` empty state instead of a blank buffer.
sourceraw docstring

local-branchesclj

(local-branches root)

Local branches as [{:name :current?}], current first.

Local branches as `[{:name :current?}]`, current first.
sourceraw docstring

log-graph-linesclj

(log-graph-lines root)
(log-graph-lines root {:keys [all? max] :or {max 250}})

Pretty git log --graph for the fullscreen log viewer, as ANSI-colored lines (git's own --color=always graph). opts:

  • :all? include every ref, not just HEAD's history (default false)
  • :max commit cap (default 250). Returns a vec of lines; a one-line notice when the repo has no commits.
Pretty `git log --graph` for the fullscreen log viewer, as ANSI-colored
lines (git's own `--color=always` graph). `opts`:
- `:all?` include every ref, not just HEAD's history (default false)
- `:max`  commit cap (default 250).
Returns a vec of lines; a one-line notice when the repo has no commits.
sourceraw docstring

multi-status-rowsclj

(multi-status-rows repos expanded diff-fn)

Rows for one OR many repos. repos is [{:root :label :draft? :model}] (:model a status-model, nil outside a git repo). ONE repo renders exactly like status-rows — the single-root buffer looks unchanged — while several repos each get a :repo header row. EVERY row is tagged with its :root so the dialog's verbs route to the right repo.

In a MULTI-root buffer only the repos with something to act on unfold (repo-open?); a clean repo is its header line alone until TAB opens it, so a mega-repo of a dozen clones opens as a dozen readable lines instead of a dozen commit logs.

expanded is a set of [root area path] triples — [root :repo nil] flips a repo's own fold; diff-fn receives the root-tagged file row.

Rows for one OR many repos. `repos` is `[{:root :label :draft? :model}]`
(`:model` a `status-model`, nil outside a git repo). ONE repo renders
exactly like `status-rows` — the single-root buffer looks unchanged —
while several repos each get a `:repo` header row. EVERY row is tagged
with its `:root` so the dialog's verbs route to the right repo.

In a MULTI-root buffer only the repos with something to act on unfold
(`repo-open?`); a clean repo is its header line alone until TAB opens it, so
a mega-repo of a dozen clones opens as a dozen readable lines instead of a
dozen commit logs.

`expanded` is a set of `[root area path]` triples — `[root :repo nil]` flips
a repo's own fold; `diff-fn` receives the root-tagged file row.
sourceraw docstring

nested-rootsclj

(nested-roots root)
(nested-roots root opts)

Repo entries for EVERY Git repository nested BELOW root — the clones a mega-repo keeps under repositories/, all of them, not a first dozen. The root itself is dropped — workspace-roots already owns it — and each entry is labelled by its path RELATIVE to the session root, so a mega-repo reads as repositories/svar and not as a second svar. Never throws: a missing or unreadable root yields no entries.

Repo entries for EVERY Git repository nested BELOW `root` — the clones a
mega-repo keeps under `repositories/`, all of them, not a first dozen. The
root itself is dropped — `workspace-roots` already owns it — and each entry
is labelled by its path RELATIVE to the session root, so a mega-repo reads as
`repositories/svar` and not as a second `svar`. Never throws: a missing or
unreadable root yields no entries.
sourceraw docstring

nested-scan-limitclj

Ceiling on the repositories the discovery WALK may find below the session root. NOT a display limit: every repository the walk finds earns its own header, however many that is — a mega-repo of forty clones opens as forty rows. A walk over an unknown tree has to terminate somewhere, and when this bound (or the budget below) does bite, the buffer SAYS so (nested-scan-truncated?) instead of quietly showing fewer repositories.

Ceiling on the repositories the discovery WALK may find below the session
root. NOT a display limit: every repository the walk finds earns its own
header, however many that is — a mega-repo of forty clones opens as forty
rows. A walk over an unknown tree has to terminate somewhere, and when this
bound (or the budget below) does bite, the buffer SAYS so
(`nested-scan-truncated?`) instead of quietly showing fewer repositories.
sourceraw docstring

nested-scan-truncated?clj

(nested-scan-truncated? root)
(nested-scan-truncated? root opts)

Did discovery stop on its own budget rather than on the end of the tree? Then repositories exist below root that this buffer is NOT showing, and the dialog title carries scan truncated: a short list must never be mistaken for a complete one. Reads the SAME cached scan nested-roots did, so it costs a map lookup.

Did discovery stop on its own budget rather than on the end of the tree? Then
repositories exist below `root` that this buffer is NOT showing, and the
dialog title carries `scan truncated`: a short list must never be mistaken
for a complete one. Reads the SAME cached scan `nested-roots` did, so it
costs a map lookup.
sourceraw docstring

next-sectionclj

(next-section rows idx dir)

Index of the nearest :section/:repo header from idx moving by dir (+1/-1); idx unchanged when there is none that way. Magit's n/p section-to-section jump.

Index of the nearest `:section`/`:repo` header from `idx` moving by `dir`
(+1/-1); `idx` unchanged when there is none that way. Magit's `n`/`p`
section-to-section jump.
sourceraw docstring

next-selectableclj

(next-selectable rows idx dir)

Index of the nearest selectable row moving from idx by dir (+1/-1); returns idx unchanged when there is none further that way.

Index of the nearest selectable row moving from `idx` by `dir` (+1/-1);
returns `idx` unchanged when there is none further that way.
sourceraw docstring

pull!clj

(pull! root)
source

push!clj

(push! root {:keys [set-upstream? force? remote dry-run? no-verify?]})

opts: :remote (default "origin"), :set-upstream? adds -u <remote> <branch>, :force? uses --force-with-lease (never bare --force), :dry-run? adds --dry-run, :no-verify? adds --no-verify to skip pre-push hooks.

`opts`: :remote (default "origin"), :set-upstream? adds `-u <remote> <branch>`,
:force? uses `--force-with-lease` (never bare --force), :dry-run? adds
`--dry-run`, :no-verify? adds `--no-verify` to skip pre-push hooks.
sourceraw docstring

range-commitsclj

(range-commits root range-spec)

Commits in range-spec (e.g. "@{upstream}..HEAD") as [{:sha :subject}], newest first. Empty when the range is empty or unresolvable.

Commits in `range-spec` (e.g. "@{upstream}..HEAD") as `[{:sha :subject}]`,
newest first. Empty when the range is empty or unresolvable.
sourceraw docstring

recent-commitsclj

(recent-commits root n)

Latest n commits as [{:sha :subject}], newest first.

Latest `n` commits as `[{:sha :subject}]`, newest first.
sourceraw docstring

refs-for-specclj

(refs-for-spec branch topic)

PURE: the Gerrit push refspec HEAD:refs/for/<branch>, with an optional %topic=<topic> appended when topic is non-blank.

PURE: the Gerrit push refspec `HEAD:refs/for/<branch>`, with an optional
`%topic=<topic>` appended when `topic` is non-blank.
sourceraw docstring

remotesclj

(remotes root)

Configured remotes as [{:name :url}] (the PUSH url), in git's own order. Deduplicated so a remote with distinct fetch/push urls shows once.

Configured remotes as `[{:name :url}]` (the PUSH url), in git's own order.
Deduplicated so a remote with distinct fetch/push urls shows once.
sourceraw docstring

repo-dirty?clj

(repo-dirty? {:keys [untracked unstaged staged unmerged unpushed unpulled]})

Has this repo anything to show? Working-tree changes, a conflict, or commits waiting to be pushed or pulled. A clean repo's sections are all empty except its recent history, which is why the multi-root buffer folds it shut.

Has this repo anything to show? Working-tree changes, a conflict, or commits
waiting to be pushed or pulled. A clean repo's sections are all empty except
its recent history, which is why the multi-root buffer folds it shut.
sourceraw docstring

repo-open?clj

(repo-open? expanded root model)

Is this repo's section stack unfolded in a multi-root buffer? A repo with something to act on opens by default and a clean one shows as its header alone; TAB on the header flips either way by putting [root :repo nil] in expanded — the same flip-a-default rule section-open? uses.

Is this repo's section stack unfolded in a multi-root buffer? A repo with
something to act on opens by default and a clean one shows as its header
alone; TAB on the header flips either way by putting `[root :repo nil]` in
`expanded` — the same flip-a-default rule `section-open?` uses.
sourceraw docstring

repo-rowclj

(repo-row {:keys [label root draft? model collapsed?]})

The repo header row a multi-root buffer shows above each repo's sections: a fold marker, the repo's label, and repo-summary — so a FOLDED repo still says which branch it is on and how dirty it is.

The repo header row a multi-root buffer shows above each repo's sections: a
fold marker, the repo's label, and `repo-summary` — so a FOLDED repo still
says which branch it is on and how dirty it is.
sourceraw docstring

repo-summaryclj

(repo-summary {:keys [branch detached? head untracked unstaged staged unmerged
                      ahead behind]
               :as model})

One line of state for a repo header: branch (or detached sha), then the working-tree buckets that hold something — clean when none do — then ahead/behind. Same vocabulary as the Head:/Merge: preamble, so a folded repo reads like the buffer it opens into.

One line of state for a repo header: branch (or detached sha), then the
working-tree buckets that hold something — `clean` when none do — then
ahead/behind. Same vocabulary as the `Head:`/`Merge:` preamble, so a folded
repo reads like the buffer it opens into.
sourceraw docstring

section-ofclj

(section-of rows section-idx)

The [area path]-bearing rows covered by a :section header row — used for section-wide stage/unstage (s/u on the header). Stops at the next :section OR :repo header and only matches rows of the SAME repo (:root), so a multi-root buffer never bleeds one repo's files into another's section.

The `[area path]`-bearing rows covered by a `:section` header row —
used for section-wide stage/unstage (`s`/`u` on the header). Stops at the
next `:section` OR `:repo` header and only matches rows of the SAME repo
(`:root`), so a multi-root buffer never bleeds one repo's files into
another's section.
sourceraw docstring

section-open?clj

(section-open? expanded area)

Is area's section currently expanded? expanded carries [:section area] toggle keys that FLIP a section from its default — a default-collapsed section (stash list, commit log) opens when its key is present; a default-open working-tree section closes when its key is present.

Is `area`'s section currently expanded? `expanded` carries `[:section area]`
toggle keys that FLIP a section from its default — a default-collapsed
section (stash list, commit log) opens when its key is present; a
default-open working-tree section closes when its key is present.
sourceraw docstring

selectable?clj

(selectable? {:keys [kind stageable?]})

Rows the dialog cursor can land on. A :diff row is landable only when it is :stageable? (a hunk of a staged/unstaged file), so plain diff peeks stay scroll-only.

Rows the dialog cursor can land on. A `:diff` row is landable only when it is
`:stageable?` (a hunk of a staged/unstaged file), so plain diff peeks stay
scroll-only.
sourceraw docstring

session-rootsclj

(session-roots ws fallback-root)
(session-roots ws fallback-root catalog)

Every repository the status buffer shows for a session, in one list:

  1. the primary workspace root (workspace-roots) — it owns the title and the fallback root, so it stays FIRST;
  2. every Git repository nested BELOW it (nested-roots) — the clones a mega-repo keeps in a repositories/ folder, or any repo checked out inside the project outside .gitmodules;
  3. every repository DECLARED in vis.yml's workspace.filesystem catalog (configured-roots) — the sibling checkouts bound to the session from elsewhere on the filesystem.

The list is DEDUPLICATED twice over, first occurrence winning. By repository (distinct-roots): a sibling that is also nested, a root declared under another spelling of its directory, and the trunk a drafted session already shows as its clone each earn exactly one header. Then by NAME (unique-labels): two repos that would render the same header text are told apart by as much of their path as it takes, because the header is all the cursor has to say which repository a verb is about to stage, commit or push.

Roots that turn out not to be git repositories are dropped later, by load-repos. Pass catalog explicitly to resolve against something other than the live config.

Every repository the status buffer shows for a session, in one list:

1. the primary workspace root (`workspace-roots`) — it owns the title and the
   fallback root, so it stays FIRST;
2. every Git repository nested BELOW it (`nested-roots`) — the clones a
   mega-repo keeps in a `repositories/` folder, or any repo checked out inside
   the project outside `.gitmodules`;
3. every repository DECLARED in `vis.yml`'s `workspace.filesystem` catalog
   (`configured-roots`) — the sibling checkouts bound to the session from
   elsewhere on the filesystem.

The list is DEDUPLICATED twice over, first occurrence winning. By repository
(`distinct-roots`): a sibling that is also nested, a root declared under
another spelling of its directory, and the trunk a drafted session already
shows as its clone each earn exactly one header. Then by NAME
(`unique-labels`): two repos that would render the same header text are told
apart by as much of their path as it takes, because the header is all the
cursor has to say which repository a verb is about to stage, commit or push.

Roots that turn out not to be git repositories are dropped later, by
`load-repos`. Pass `catalog` explicitly to resolve against something other
than the live config.
sourceraw docstring

split-diff-hunksclj

(split-diff-hunks lines)

PURE: split a unified diff (as lines, WITH its diff --git/index/---/ +++ preamble) into {:header [lines] :hunks [[lines] ...]} — the preamble shared by every hunk, then one line-vector per @@ hunk. A valid one-hunk patch for hunk N is therefore (into header (nth hunks N)), which git apply accepts. Header is everything before the first @@; each hunk runs from its @@ line up to (not including) the next one.

PURE: split a unified diff (as `lines`, WITH its `diff --git`/`index`/`--- `/
`+++ ` preamble) into `{:header [lines] :hunks [[lines] ...]}` — the preamble
shared by every hunk, then one line-vector per `@@` hunk. A valid one-hunk
patch for hunk N is therefore `(into header (nth hunks N))`, which `git apply`
accepts. Header is everything before the first `@@`; each hunk runs from its
`@@` line up to (not including) the next one.
sourceraw docstring

stage-all!clj

(stage-all! root)
source

stage-file!clj

(stage-file! root path)
source

stage-hunk!clj

(stage-hunk! root {:keys [path hunk]})

Magit's s on a diff HUNK: stage just hunk hunk (0-based, in @@ order) of path's UNSTAGED diff — reconstruct that one hunk into a patch and git apply --cached it, leaving the file's other hunks unstaged.

Magit's `s` on a diff HUNK: stage just hunk `hunk` (0-based, in `@@` order) of
`path`'s UNSTAGED diff — reconstruct that one hunk into a patch and
`git apply --cached` it, leaving the file's other hunks unstaged.
sourceraw docstring

stash-apply!clj

(stash-apply! root ref)
source

stash-diff-linesclj

(stash-diff-lines root {:keys [ref]})

Diff body for one stash row, as plain lines (for the TAB fold): the patch git stash show -p produces for ref, from the first diff --git header down so every file the stash touched is named.

Diff body for one stash row, as plain lines (for the TAB fold): the patch
`git stash show -p` produces for `ref`, from the first `diff --git` header
down so every file the stash touched is named.
sourceraw docstring

stash-drop!clj

(stash-drop! root ref)
source

stash-pop!clj

(stash-pop! root ref)
source

stash-push!clj

(stash-push! root message)

Stash the working tree INCLUDING untracked files (the least surprising default for a status-buffer 'stash everything' verb). Git exits 0 with 'No local changes to save' when there is nothing to stash — surface that as a failure so the dialog doesn't claim success.

Stash the working tree INCLUDING untracked files (the least surprising
default for a status-buffer 'stash everything' verb). Git exits 0 with
'No local changes to save' when there is nothing to stash — surface that
as a failure so the dialog doesn't claim success.
sourceraw docstring

stashesclj

(stashes root)

Stash list as [{:ref "stash@{0}" :message}], newest first.

Stash list as `[{:ref "stash@{0}" :message}]`, newest first.
sourceraw docstring

status-modelclj

(status-model root)

One full magit snapshot of the repo at root, or nil outside a repo.

{:branch :detached? :head :upstream? :upstream :ahead :behind :head-subject :untracked [path …] :unstaged [{:path :code} …] ;; worktree side (porcelain Y) :staged [{:path :code} …] ;; index side (porcelain X) :unmerged [{:path :code} …] :stashes [{:ref :message} …] :unpushed [{:sha :subject} …] ;; @{upstream}..HEAD — magit's Unmerged into :unpulled [{:sha :subject} …] ;; HEAD..@{upstream} — magit's Unpulled from :commits [{:sha :subject} …]}

One full magit snapshot of the repo at `root`, or nil outside a repo.

{:branch :detached? :head :upstream? :upstream :ahead :behind
 :head-subject
 :untracked [path …]
 :unstaged  [{:path :code} …]     ;; worktree side (porcelain Y)
 :staged    [{:path :code} …]     ;; index side   (porcelain X)
 :unmerged  [{:path :code} …]
 :stashes   [{:ref :message} …]
 :unpushed  [{:sha :subject} …]   ;; @{upstream}..HEAD — magit's `Unmerged into`
 :unpulled  [{:sha :subject} …]   ;; HEAD..@{upstream} — magit's `Unpulled from`
 :commits   [{:sha :subject} …]}
sourceraw docstring

status-rowsclj

(status-rows model expanded)
(status-rows {:keys [untracked unstaged staged unmerged stashes commits upstream
                     unpushed unpulled]
              :as model}
             expanded
             diff-fn)

PURE projection: model (+ expanded set of [area path], + optional diff-fn row→lines) → renderable rows. Every row is {:kind :info|:section|:file|:diff|:stash|:commit|:blank :text …}. Section order mirrors magit: unpushed commits render as Unmerged into <upstream> and Recent commits appears ONLY when nothing is unpushed (magit's unpushed-to-upstream-or-recent); Unpulled from <upstream> closes the buffer when the branch is behind.

PURE projection: model (+ `expanded` set of `[area path]`, + optional
`diff-fn` row→lines) → renderable rows. Every row is
`{:kind :info|:section|:file|:diff|:stash|:commit|:blank :text …}`.
Section order mirrors magit: unpushed commits render as
`Unmerged into <upstream>` and `Recent commits` appears ONLY when nothing
is unpushed (magit's `unpushed-to-upstream-or-recent`); `Unpulled from
<upstream>` closes the buffer when the branch is behind.
sourceraw docstring

unstage-all!clj

(unstage-all! root)
source

unstage-file!clj

(unstage-file! root path)

Magit's u: git reset -q -- path. Unlike restore --staged this also works on an unborn HEAD (before the first commit), exactly like magit.

Magit's `u`: `git reset -q -- path`. Unlike `restore --staged` this also
works on an unborn HEAD (before the first commit), exactly like magit.
sourceraw docstring

unstage-hunk!clj

(unstage-hunk! root {:keys [path hunk]})

Magit's u on a staged diff HUNK: unstage just hunk hunk (0-based) of path's STAGED diff — reverse-apply that one hunk to the index.

Magit's `u` on a staged diff HUNK: unstage just hunk `hunk` (0-based) of
`path`'s STAGED diff — reverse-apply that one hunk to the index.
sourceraw docstring

upstream-nameclj

(upstream-name root)

Short name of the current branch's upstream (origin/main), or nil.

Short name of the current branch's upstream (`origin/main`), or nil.
sourceraw docstring

visit-file-linesclj

(visit-file-lines root path)

Working-tree content of path (relative to root) as plain lines for the fullscreen RET-visit viewer, or nil when it isn't a readable regular file (a deleted/renamed entry has no working-tree body — the caller falls back to the diff).

Working-tree content of `path` (relative to `root`) as plain lines for the
fullscreen `RET`-visit viewer, or nil when it isn't a readable regular file
(a deleted/renamed entry has no working-tree body — the caller falls back to
the diff).
sourceraw docstring

workspace-rootsclj

(workspace-roots ws fallback-root)

The single repository entry the magit buffer shows for a session. A draft's :root is its working clone and :repo-root remains its trunk. Accepts the gateway workspace map in either in-process kebab or canonical snake shape.

The single repository entry the magit buffer shows for a session. A draft's
`:root` is its working clone and `:repo-root` remains its trunk. Accepts the
gateway workspace map in either in-process kebab or canonical snake shape.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close