Repository navigation
How the Git Menu Works
The Git menu of the native menu bar holds every git command. This chapter covers what decides its state, what its items run, the Current File tabs, patches and GitHub links. The user side is in Git Menu. The menu bar itself is in How the menus work, and the dialogs it opens in How the Git dialogs work.
The user asked for one Git menu: one place for every command, with familiar keys (Cmd+K, Cmd+T, Cmd+9, Option+Cmd+A). It also made room in the header, whose Fetch, Pull, Push and Stash buttons moved into this menu (see How remotes work). The Current File submenu adds per-file history and compares that the app did not have.
flowchart LR
Stores["repoStore, fileCommands, settings"] --> Inputs["gitRepoInputs()<br/>gitFileInputs()"]
Inputs --> State["gitMenuState(repo, file, blameGutter)"]
State --> Menu["appMenu: enabled, text, visible"]
gitMenuInputs.ts reads the active repository (busy, ahead, behind, branch, unborn, operation, conflicts, changes, remotes, a github.com remote) and the file on screen (changed, untracked, staged or not, conflicted). gitMenuState in menuState.ts turns that into the item states:
-
Ready means a repository that is not busy. Push and Pull also need a branch, a remote and no operation in progress.
countLabelnames them Push (2 ahead)... and Pull (1 behind).... -
Operation items are
visibleonly during a merge, rebase, cherry-pick or revert, and named after it (OPERATION_NAMES): Continue Rebase, Abort Rebase. Continue stays grey while conflicts remain, Resolve Conflicts shows only with conflicts, and Skip Commit only in a rebase. - Current File items need a file tab inside a repository. History and compare items need a tracked file; Rollback File needs a change that is not a conflict.
- GitHub shows for every repository, because Share Project is for one without a GitHub remote. The link items need a github.com remote.
menuActions.ts wraps each handler in git(...) (an active repository that is not busy), workspace(...) or, for Clone (which works from the welcome screen), app(...), then calls gitMenuActions.ts. That module reuses what the views already do:
| Item | Runs |
|---|---|
| Commit... |
focusCommitMessage in gitActions.ts
|
| Fetch, Fetch All Remotes, Force Push..., Stash Changes... |
fetchRemote, fetchAll, push(true), stash in gitActions.ts
|
| Merge..., Rebase..., Branches..., New Tag... |
mergeBranch, rebaseBranch, openBranchPicker, createTag in changes/repoActions.ts
|
| New Branch..., Unstash Changes... |
newBranchFrom, applyStash in sidebar/actions.ts
|
| Continue, Abort, Skip Commit |
operationActions.ts, shared with the banner (OpBanner.svelte) |
| Push..., Pull..., Reset HEAD..., Rollback..., Manage Remotes..., Clone..., Update Project... | gitDialogs.open(...) |
| Cherry-Pick..., Interactive Rebase... | a commit picker (pickCommit, 200 commits), then cherry_pick or the Interactive Rebase dialog |
Compare with Revision, Compare with Branch, Show History and Show History for Selection open in editor tabs. Like commit tabs, each has a pseudo path that can never be a file (stores/gitTabs.ts), such as git-fileHistory:<repo>|<file>. GitTab.svelte picks the view:
-
FileHistoryTab.sveltepages throughfile_history, which runsgit log --followso renames are followed. The selected commit shows inCommitDetails. -
LineHistoryTab.sveltecallsline_history, which runsgit log -L start,end:file. The UI library'sPatchViewcolors each patch (itslogic/patchLines.tssplits it into lines).git log -Lcounts lines in HEAD (the last commit), soshowSelectionHistoryfirst maps the editor's selection withheadLineRange(views/git/lineHistoryRange.ts): it diffs the committed text against the editor text withdiffLinesand keeps the committed lines the selection covers. When every selected line is new, a toast says so instead of opening a tab. -
CompareTab.sveltegetscompare_with_revision(the file at a revision against the work tree) and shows it in a read-onlyDiffView.
The two history commands live in src-tauri/src/git/history.rs and use the git CLI, because libgit2 can neither follow renames nor trace a line range.
flowchart TD
Apply["apply_patch(file or text)"] --> Check{"git apply --check"}
Check -->|"ok"| Plain["git apply: work tree only"]
Check -->|"fails"| Three["git apply --3way"]
Three -->|"ok or conflicts"| Done["OpOutcome, conflicts open in Changes"]
Three -->|"fails"| Error["Patch does not apply: reason"]
-
create_patchrunsgit diff(HEAD to index, index to work tree, or HEAD to work tree; the empty tree before the first commit) andcreate_commit_patchrunsgit format-patch -1 --stdout. Both add--binaryand explicita/b/prefixes, so a user'sdiff.noprefixnever breaks the patch. -
apply_patchapplies to the work tree only. If that fails, a 3-way merge can still apply it with conflicts, using the base blobs the patch names. -
read_clipboard_textreads the clipboard natively (pbpasteon macOS), because the web view only allows a clipboard read right after a click in the page. The frontend checks the text looks like a patch first.
Open Repository in Browser and the GitHub link items only build URLs and open them. How they read remote URLs is in Git Menu Links.
| File | What it does |
|---|---|
src/lib/menu/menuState.ts |
gitMenuState, countLabel
|
src/lib/views/git/gitMenuInputs.ts |
Inputs read from the stores, currentGitFile
|
src/lib/views/git/gitMenuActions.ts |
What each item does |
src/lib/views/git/operationActions.ts |
Continue, Abort, Skip Commit |
src/lib/views/git/github.ts, remoteLinks.ts
|
Links to the remote's pages, see Git Menu Links |
src/lib/stores/gitTabs.ts, src/lib/views/git/GitTab.svelte and its tabs |
Current File tabs |
src-tauri/src/commands/patch.rs |
Patch commands and the clipboard read |
src-tauri/src/commands/history.rs, src-tauri/src/git/history.rs
|
File and line history, compare |
One function per action, shared. A menu item calls the same code as its button in Changes, the banner or the Log, so they cannot drift apart.
Hide what does not apply. Operation items appear only during an operation, instead of sitting grey.
History in tabs. Show History and compares open as editor tabs, so several can stay open next to the code, with Back and Forward.
Links without an account. Open on GitHub and friends only build URLs; the account features are separate (see How GitHub works).
Show History for Selection traced the wrong lines.
- The issue: with uncommitted lines added or deleted above the selection, the tab showed the history of other lines.
-
Why it happened: the menu passed the editor's line numbers, but
git log -Lreads them against HEAD. -
The fix and why we chose it:
headLineRangemaps the selection to HEAD lines before the tab opens, with the same line diff as the change markers, and only new lines give a message. Mapping in the frontend uses the unsaved editor text, which the backend never sees; the tab keeps HEAD numbers, so Refresh stays right while you keep editing.
-
src/lib/menu/menuState.test.ts, "Git menu": ahead and behind labels, branch and remote rules, operation items, Current File rules, GitHub and Clone. -
src/lib/views/git/github.test.tsandremoteLinks.test.ts(see Git Menu Links),lineHistoryRange.test.ts(inserted, deleted, modified and only new lines) andsrc/lib/stores/gitTabs.test.ts. -
src-tauri/src/commands/patch.rs:create_patch_writes_the_chosen_changes,create_patch_works_before_the_first_commit,a_commit_patch_applies_elsewhere,apply_patch_falls_back_to_a_three_way_merge,apply_patch_reports_why_it_does_not_applyandapply_patch_from_text. -
src-tauri/src/commands/history.rs:file_history_follows_renames_page_by_page,line_history_traces_a_rangeandcompare_with_revision_reads_the_old_version.
The native menu itself needs a manual check. See Testing.
- New items follow the steps in How the menus work, with a
gitMenuStaterule and test. - Update Git Menu and retake its screenshots (
git-menu-*.png). See Docs and Screenshots.
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