git-cli
| (require git-cli) | package: git-cli |
The git-cli module provides a command-line-like Git interface implemented by invoking the git executable. Commands do not allow Git to read credentials or other answers from the terminal.
1 Command interface
syntax
(git command argument ...)
Registered command symbols include 'init, 'status, 'add, 'commit, 'push, 'pull, 'fetch, 'config, 'branch, 'remote, 'stash, 'restore, 'reset, 'revert, 'rebase, 'merge, 'cherry-pick, 'mergetool, 'switch, 'clone, 'tag, 'log, 'rev-list, 'diff, 'show, 'grep, 'help, 'version, and 'new-version.
When no wrapper is registered, the command and arguments are passed directly to the installed Git executable through run-git. The result is handled by the same standard result processing used by ordinary pass-through wrappers: normal Git output is displayed and a successful command returns #t; a non-zero exit status raises a git-cli error.
This makes dedicated wrappers optional for Git commands where git-cli does not add useful behavior.
(git 'blame "main.rkt") (git* clean -n) (git* worktree list) (git* archive --format=zip HEAD)
Some registered commands process the result into a Racket value, such as 'status, 'grep, 'log with –list, 'version, and 'new-version.
syntax
(git* command argument ...)
(git* remote -v) (git* switch main)
An argument written as (eval expression) is evaluated instead of being converted from its literal syntax.
(define branch "develop") (git* switch (eval branch))
Important: bare arguments to git* are command-line text, not Racket values. An identifier is quoted syntactically and converted to a string, even when that identifier is also bound to a Racket variable or procedure.
(define branch "develop") (git* switch branch) (git* switch (eval branch))
This distinction matters most for git-cli commands whose arguments are not ordinary Git command-line strings. Such wrappers should accept the textual arguments produced by git*. For example, git-new-version now accepts both symbols and text:
(git 'new-version 'min) (git* new-version min)
Because git falls back to direct Git execution for commands without a registered wrapper, git* can also be used with those commands.
gt is retained as a compatibility alias for git*.
2 Rash integration
Rash integration is provided by the separate rash-git-cli package. The git-cli package itself does not depend on Rash or Linea.
3 Provided commands
(git-init) (git* init) (git* init --bare)
procedure
(git-status argument ...) → list?
argument : any/c
Each result item has the form (index-status worktree-status file). The index status describes the change staged for the next commit. The worktree status describes the change in the working tree relative to the index.
Both statuses are one of 'unchanged, 'modified, 'type-changed, 'added, 'deleted, 'renamed, 'copied, 'unmerged, 'untracked, or 'ignored. For an untracked file, Git reports ??, so both statuses are 'untracked.
'((modified unchanged "staged.rkt") (unchanged modified "working-tree.rkt") (modified modified "both.rkt") (renamed unchanged "old.rkt -> new.rkt") (untracked untracked "new.rkt"))
procedure
(git-commit argument ...) → boolean?
argument : any/c
For example:
(git-fetch) (git-fetch '--prune) (git 'fetch '--prune)
procedure
(git-config argument ...) → any/c
argument : any/c
(git 'config '--all) (git 'config 'get '--all) (git 'config '--global 'get '--all) (git 'config 'get '--global '--all)
returns all visible configuration entries as key/value items:
'(("user.name" "Hans Dijkema") ("user.email" "hans@example.invalid") ("credential.helper" "manager"))
(git 'config 'get "credential.helper")
returns one value as a string, or #f when the key is absent.
(git 'config 'get '--all "credential.helper")
returns all values for one key as a list. An absent key produces the empty list.
Configuration values can be written with 'set!:
(git 'config 'set! "user.email" "hans@example.invalid") (git 'config '--global 'set! "user.email" "hans@example.invalid") (git 'config 'set! '--global "user.email" "hans@example.invalid")
The optional scope can be –global, –local, or –system. It may appear directly after 'config or directly after 'get / 'set!. A successful write returns #t.
3.1 git-cli editor configuration
The git-config procedure also recognizes the git-cli-specific editor operation. This does not write Git’s core.editor; it controls the editor command used by git-cli through GIT_EDITOR and GIT_SEQUENCE_EDITOR.
With no additional argument an interactive selection is displayed.
(git* config editor)
The available editors can also be returned without prompting.
(git* config editor --list) (git* config editor --downloads)
Each item contains the short editor name, description, command and a boolean indicating whether that command is currently selected.
A detected editor can be selected by its short name, or automatic detection can be restored.
(git* config editor vscode) (git* config editor notepad++) (git* config editor auto)
An arbitrary editor command can be supplied using the ordinary procedure form.
(git 'config 'editor "C:\\Program Files\\MyEditor\\editor.exe --wait")
Changing the editor updates both GIT_EDITOR and GIT_SEQUENCE_EDITOR immediately for subsequent Git commands.
procedure
(find-editors) → list?
procedure
procedure
On Windows, Notepad++ is detected both on PATH and in the normal Program Files locations. git-cli invokes it with -multiInst -nosession.
3.2 git-cli merge tool configuration
The git-config procedure also recognizes the git-cli-specific mergetool operation.
(git* config mergetool) (git* config mergetool --list) (git* config mergetool --downloads) (git* config mergetool winmerge) (git* config mergetool auto)
With no additional argument an interactive selection is displayed. –list returns (name description path current?) items and –downloads returns official download pointers. A detected merge tool can be selected by its short Git tool name. auto clears the explicit git-cli selection and restores automatic detection.
procedure
(find-mergetools) → list?
procedure
procedure
procedure
(git-branch argument ...) → (or/c boolean? list?)
argument : any/c
With Git’s -l or –list option, git-cli returns structured branch information. Each item starts with one of 'current, 'local, or 'remote, followed by the branch name.
(git-branch '-l) '((current "main") (local "develop"))
Git’s normal branch selection and sorting options are passed through. For example, remote branches can be requested with -r, all branches with -a, and Git’s –sort=<key> option controls the returned order.
(git 'branch '-l '-a "--sort=refname") '((current "main") (local "develop") (remote "origin/main"))
procedure
(git-remote argument ...) → any/c
argument : any/c
With no arguments, the remote names are returned as a Racket list.
(git-remote) '("origin" "upstream")
With top-level -v or –verbose, each line reported by Git is returned as a separate structured item containing the remote name, URL, and the 'fetch or 'push role.
(git-remote '-v) '(("origin" "https://example.invalid/project.git" fetch) ("origin" "https://example.invalid/project.git" push))
The two Git lines are deliberately not merged. This keeps the result close to the output and semantics of git remote -v.
For get-url, one URL is returned as a string. With –all, a list of URLs is returned.
(git 'remote 'get-url "origin") (git 'remote 'get-url '--all "origin") (git 'remote 'get-url '--push '--all "origin")
git stash list is returned as structured Racket data. Each item contains the stash reference and Git’s stash description.
(git-stash 'list) '(("stash@{0}" "WIP on main: 1234567 Example") ("stash@{1}" "On main: older work"))
The structured form is only used when the caller has not supplied a –format or –pretty option. Explicit Git formatting is left unchanged.
Other stash subcommands, including push, show, pop, apply, drop, clear, branch, create, store, export, and import, are passed to Git unchanged.
procedure
(git-restore argument ...) → boolean?
argument : any/c
(git-restore "main.rkt") (git-restore '--staged "main.rkt") (git* restore --source=HEAD~1 main.rkt)
(git-reset '--hard 'HEAD) (git* reset --soft HEAD~1)
procedure
(git-revert argument ...) → boolean?
argument : any/c
(git-revert 'HEAD) (git* revert --abort)
procedure
(git-rebase argument ...) → boolean?
argument : any/c
(git-rebase "main") (git* rebase --continue) (git* rebase --abort)
(git-merge "feature") (git* merge --abort)
procedure
(git-cherry-pick argument ...) → boolean?
argument : any/c
(git-cherry-pick "abc1234") (git* cherry-pick --continue)
procedure
(git-mergetool argument ...) → boolean?
argument : any/c
(git-mergetool) (git* mergetool --tool=meld)
procedure
(find-editor) → (or/c string? #f)
procedure
(set-editor! command) → any/c
command : string?
procedure
(find-mergetool) → (or/c string? #f)
procedure
(find-mergetool-path) → (or/c path? #f)
procedure
(set-mergetool! tool) → any/c
tool : string?
procedure
(git-switch argument ...) → boolean?
argument : any/c
(git-switch "main") (git-switch '-c "feature") (git 'switch "main")
When -l or –list is supplied, the matching tag names are returned as a Racket list. Git’s sorting options are passed through unchanged, so the returned list keeps Git’s order.
(git-tag '-l) (git-tag '--list "--sort=version:refname") (git-tag '--list "--sort=-creatordate")
When -n or -n1 is combined with -l or –list, each result item contains the tag name and the subject reported by Git.
(git-tag '-l '-n) '(("v0.3.16" "Release 0.3.16") ("v0.3.17" "Release 0.3.17"))
With -n<number> and a number greater than one, git-cli asks Git for that many content lines using %(contents:lines=<number>). The returned message is kept as one string, including embedded newlines.
For structured tag output git-cli asks Git for an explicit format using %(refname:strip=2) and either %(contents:subject) or %(contents:lines=<number>). Generated field and record delimiters are used to split the result safely.
procedure
(git-rev-list argument ...) → boolean?
argument : any/c
By default a successful diff is rendered as HTML in the default browser. The git-cli-specific option –output=- keeps Git’s textual output on standard output. –output=string returns the textual diff as a string.
(git-diff) (git-diff '--cached) (git-diff '--output=-) (git-diff '--output=string)
The git-cli-specific option –list, or its short form -l, changes the result to a Racket list. Internally this option is replaced by Git’s –oneline option. Each returned item contains the abbreviated commit id and the commit subject.
(git-log '--list '-5) '(("003f371" "Diverse commando's toegevoegd. Ik weet nog niet of ik ze allemaal ga houden") ("2cb7e93" "Small changes. git main function is now a real function, not syntax"))
Other Git log options are still passed to Git. Consequently, options that add extra output lines can also influence how useful –list is as a structured result.
For a commit that includes a patch, the default git-cli output is HTML. The commit information is shown above the diff and the diff is rendered using the same Diff2Html presentation as git-diff.
The git-cli-specific output options are –output=html, –output=-, and –output=string. –output=html explicitly selects the HTML presentation, –output=- keeps Git’s normal textual output, and –output=string returns that textual output as a string. Options such as –stat, –name-only, –name-status, and –no-patch default to textual output because they do not normally contain a patch.
The git-cli-specific option –list, or its short form -l, returns a Racket value. Without another show-format option it implies –stat.
(git-show '-l "9741b1c")
The result of –stat –list contains 'file and 'total items:
'((file "README.md" 67 "+++---") (file "main.rkt" 532 "++++-------------------------------------------") (total 9 124 823))
With –name-only –list, the result is a list of file names. With –name-status –list, every result item is the tab-separated Git name-status record converted to a list of strings.
–list/-l cannot be combined with –output=.... Only one of –stat, –name-only, and –name-status can be used with –list.
4 Package version
procedure
(git-version) → list?
procedure
(git-new-version kind) → list?
kind : symbol?
(git-new-version 'min) (git 'new-version 'min) (git* new-version min)
The version kind may be supplied as a symbol or string. This makes the command compatible with git*, whose bare arguments are converted to text.
5 Low-level Git execution
procedure
(run-git args [#:input input]) →
exact-integer? list? args : list? input : (or/c #f string?) = #f
The procedure returns two values: Git’s exit code and the ordered output items, where each item identifies either 'stdout or 'stderr.
(run-git '(credential fill) #:input "protocol=https\nhost=git.dijkewijk.nl\n\n")
6 Authentication retry
Git commands recognize common authentication failures immediately after the Git process finishes and before command-specific result processing takes place. Such a failure is represented by exn:fail:git-auth?.
parameter
(current-git-authentication-handler handler) → void? handler : procedure?
The callback returns a true value when it has handled authentication and the original Git command should be tried again. A command is retried at most once. The default callback is default-git-authentication-handler.
(current-git-authentication-handler (lambda (cmd args e) #t))
procedure
(exn:fail:git-auth? v) → boolean?
v : any/c
procedure
e : exn:fail:git-auth?
procedure
(exn:fail:git-auth-args e) → list?
e : exn:fail:git-auth?
procedure
e : exn:fail:git-auth?
procedure
e : exn:fail:git-auth?
7 Authentication
procedure
(default-git-authentication-handler cmd args e) → boolean? cmd : symbol? args : list? e : exn:fail:git-auth?
parameter
(current-git-authentication-handler handler) → void? handler : procedure?