Repository navigation
How the Git Console Works
The Git Console lists the git commands the app ran, with their arguments, duration, exit code and the start of their output. It is a bottom panel tab, behind the Git Console switch in Settings > Git, which is off by default. For the user side, see Git Console.
Nibtree runs every write through the git CLI (see Architecture). When a push or rebase does something unexpected, a toast shows only the error. The console shows the whole command and git's output, so it can be repeated in a terminal or pasted into a bug report.
Every runner in src-tauri/src/git/cli.rs (and the cancellable runner in git/cancel.rs, used by Clone) calls git_console::record(repo_path, args) before it spawns git. That returns a CommandRecord. When git exits, the runner calls record.finish(exit_code, stdout, stderr); when git cannot start, record.fail(error). If the record is dropped without either (an early return), its Drop marks the entry failed with "git did not finish", so no entry stays "running" forever.
sequenceDiagram
participant CLI as git/cli.rs
participant GC as git_console.rs
participant EV as "git-command" event
participant View as GitConsoleView.svelte
CLI->>GC: record(repo, args)
alt console is off
GC-->>CLI: record with no id, nothing stored
else console is on
GC->>GC: redact args, push running entry, evict oldest
GC->>EV: emit (only after the first git_console_entries)
end
CLI->>CLI: run git
CLI->>GC: finish(exit code, stdout, stderr)
GC->>GC: keep first 16 KB of each, redact, update budget
GC->>EV: emit finished entry
EV->>View: upsertEntry
GitConsole holds a VecDeque<GitCommandEntry> behind a mutex, an enabled flag and a OnceLock emitter. There is one global console (git_console::global()), and AppState.git_console points at it. Limits are constants: MAX_ENTRIES 500, MAX_OUTPUT_BYTES 16 KB per stream, MAX_TOTAL_OUTPUT_BYTES 4 MB for all entries. evict drops the oldest entries until both the count and the byte budget fit. A cut never splits a UTF-8 character, and the entry says which stream was cut.
Arguments go through redact_args and output through redact_text before they are stored. They mask the password in scheme://user:password@host, a token used as the URL user name, the value of any key=value whose key contains extraheader, password, passwd, token, secret, authorization or cookie, the word after Bearer or Basic, and tokens starting with ghp_, gho_, ghu_, ghs_, ghr_, github_pat_ or glpat-. The GitHub sign-in runs gh auth token with its own Command, outside cli.rs, so that token is never recorded (see How GitHub Works).
| Command | What it does |
|---|---|
git_console_entries |
Every entry, oldest first. The first call also sets the emitter, so "git-command" events start only once someone opened the console. |
git_console_clear |
Empties the buffer. |
git_console_set_enabled |
The setting. Off drops every entry. |
The "git-command" event carries one GitCommandEntry, once when a command starts and once when it ends. api.onGitCommand listens to it.
GitConsoleView.svelte subscribes to the event first, then loads the list and merges events that arrived meanwhile (mergeEntries). Each later event goes through upsertEntry, which never lets a late "started" event undo a finish. The list is the UI library's List with virtual and measure: only the rows in view are drawn, and an opened entry's output (up to 240 px, then it scrolls) is measured. It follows new entries unless the user scrolled up. Entries are $state.raw arrays, replaced, not mutated.
The console is off by default, and off costs close to nothing. Most people never open it, and quietly recording every git command would make the app bigger for everyone.
flowchart TD
Load["settings loaded"] --> Eff["App.svelte effect"]
Eff -->|"gitConsole false"| Off["git_console_set_enabled(false)"]
Eff -->|"gitConsole true"| On["git_console_set_enabled(true)"]
Off --> Free["buffer replaced by a new VecDeque: memory given back"]
Off --> Hide["tab, View > Git Console and Git > Show Git Console hidden"]
Off --> NoChunk["GitConsoleView chunk never imported"]
On --> Rec["record() stores entries"]
-
Rust records nothing. The global console starts disabled before settings load.
startchecks the flag under the buffer lock and returnsNone, so a command that starts while the switch flips never stays behind. With no id,finishdoes nothing: no strings are copied or kept. -
Turning it off frees memory.
clearassigns a newVecDequeinstead of callingclear(), which would keep the capacity of up to 500 entries. -
No UI code is loaded.
TerminalPanel.svelteloadsGitConsoleView.sveltewith a dynamicimport(), only when the tab shows and the setting is on. The tab itself is filtered out while off.terminalStore.showTab("gitConsole")refuses while off, andcloseGitConsole()leaves the tab when the switch turns off. -
No events before use. The emitter is set on the first
git_console_entries, so until the console is opened, nothing crosses the IPC bridge. Once set, it stays for the session (aOnceLock); an event with no listener is cheap. -
Menus follow.
menuState.tsgivesview.gitConsoleandgit.showConsolevisible: falsewhile off.
When on, the worst case is bounded: 500 entries and 4 MB of output, plus the arguments.
| File | What it does |
|---|---|
src-tauri/src/git_console.rs |
GitConsole, CommandRecord, record, limits and redaction |
src-tauri/src/commands/console.rs |
The three commands and the "git-command" emitter |
src-tauri/src/git/cli.rs, git/cancel.rs
|
Call record around every git process |
src/lib/console/GitConsoleView.svelte |
The tab: toolbar, filter, the library's virtual List (measured rows, follows the end), context menu |
src/lib/console/consoleModel.ts |
Pure list logic: merge, filter, quoting, layout |
src/lib/terminal/TerminalPanel.svelte, terminalStore.svelte.ts
|
The panel tab and showTab, toggleTab, closeGitConsole
|
src/lib/App.svelte |
Sends the setting to Rust once settings are loaded |
src/lib/stores/settingsData.ts |
gitConsole, default false
|
src/lib/views/settings/GitSettings.svelte |
The switch and Show Git Console button |
src-tauri/src/mcp/tools/git_read.rs |
The git_console_entries MCP tool, which says when the console is off |
Record in cli.rs, not per command. Every git process passes through a few runners, so one call there covers every feature, including new ones. git2 reads are not git commands and are left out on purpose.
Mask before storing. Redacting on display would leave secrets in memory and in MCP answers. Masking at record time means nothing secret is ever kept.
A record that fails on drop. Early returns with ? are common in the runners. The Drop guard keeps the list honest without touching each return.
-
src-tauri/src/git_console.rs: redaction of URLs, config values, headers and token formats; the 500 entry cap; nothing recorded while off and the list dropped; the per-stream and total output caps; a cut never splits a character; entries go from running to finished and are announced; real git commands are recorded and a dropped record is marked failed. -
src/lib/console/consoleModel.test.ts:upsertEntry,mergeEntries, quoting, durations, the filter and output blocks. -
src/lib/stores/settingsData.test.ts:gitConsoledefaults to false and only accepts a boolean. -
src/lib/menu/menuState.test.ts: the View item is hidden while off.
- Update this page when
git_console.rs,commands/console.rsor the console view change, and when a new git runner is added tocli.rs(it must callrecord). - Update Git Console for any change to the toolbar, the menu or the limits, and retake
git-console.pngandgit-console-setting.png. - Commands and the event are listed in Commands and Events; the switch in How Settings Work.
None yet.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode