Repository navigation
Architecture
Loky edited this page Oct 14, 2026
·
6 revisions
core/ holds git and GitHub logic, ui/ holds presentation only. Modules talk through signals. The engine has no knowledge of the UI, and the UI never calls OS.execute().
UI panel -> GitEngine (command API) -> GitRunner (OS.execute, threads, timeouts)
| |
command_completed(context) <-----------+
|
GitotResultRouter -> domain handlers -> panels (head_moved, files_changed, file_restored, status_parsed, branches_parsed)
A caller that only needs its own answer passes on_done to the command; command_completed still broadcasts to everyone.
| Module | Role |
|---|---|
GitEngine |
Command API. Emits command_completed with a per-call context; run_fast / run_network and the helpers built on them (fetch, pull, init_repo...) take an optional on_done(exit_code, output). Delegates execution to GitRunner. Reads that repaint a panel (STATUS, LOG, BRANCHES, STASH_LIST, AHEAD_BEHIND) are latest-wins: the result of a request that a newer one superseded is not broadcast (its on_done still runs). Also owns repo setup: init_repo() and add_remote() (refuses a URL that fails GitRemote.is_valid_url(), the one URL rule). |
GitRunner |
Process execution: worker threads, 120 s timeout, shell redirect, write lock (writes, push and pull; reads and the other network commands always run). No git-domain knowledge. Enforces SHELL_SAFE_PATTERN on network args and refuses project / log paths with characters the shell would expand. |
GitSyncOrchestrator |
push -> create tag -> push tag. plan_push() returns NORMAL, FORCE_CONFIRM or BLOCKED_BEHIND from ahead/behind counts (no git call). |
GitotRepoState |
Single source for the current branch: name, origin owner/repo and its web address, upstream / ahead / behind (changed signal). Written by the router, read by panels, the push flow and the log messages. |
GitRemote, GitRef
|
Static, no git call: remote URL rules (owner/repo, browsable address, the add_remote() whitelist) and tag / branch name rules. |
GitIgnore |
Static: creates the default Godot .gitignore only when none exists. |
GitStatusParser, GitDiffParser, GitLogParser, GitStashParser, GitBranchParser, GitLfsParser
|
Static parsers. Custom \x1f-delimited formats. They return typed entries (GitStatusEntry, GitCommitEntry, GitStashEntry, GitBranchEntry, GitLfsFile), not dictionaries; diff line kinds are the GitDiffParser.LineType enum. |
GitotResultRouter |
Dispatches each finished command: to GitotBranchResults or GitotSyncResults (each owns a COMMANDS list and a handle()), or to its own handlers (commit, stash, status, log, remote). The only place that reads command_completed; shared failure/hint texts live in GitotMessages. |
GitLfs |
Facade for LFS state, track/untrack, pull, prune. Typed signals. |
GithubAuth / GithubApi / GithubIssueParser
|
PAT storage, authenticated REST wrapper, issue JSON normalization. |
GitotSettings / GitotLogger
|
Settings storage: KEY_* constants, DEFAULTS, and RANGES (clamp and spin-box bounds). Central log with capped history, levels Info / Success / Warning / Error / Fatal / Hint / git raw, and fail() as the one failure shape. |
-
gitot_dockis the shell. Each fold (status tree, branches, shelf, history, tags, settings, console) is its own script;GitotEditorSync(editor refresh),GitotCommitFlow(commit / amend and the commit area's wording),GitotPushFlow(push; emitsremote_missingwhen there is no origin),GitotWorkingDiff,GitotRepoInit(Initialize repository button) andGitotRemotePrompt(remote URL dialog) hold the use cases. -
gitot.gdowns the editor-level registration ofGitotFileTooltip(FileSystem dock tooltip). It is fed by the dock'sstatus_parsedsignal, so it needs no git call of its own. - Bottom panels: Diff viewer, LFS. Main-screen tab: Issues.
-
gitot_result_routerroutes results to handlers so the dock stays thin. Widgets that start a command (Fetch, Pull, Delete on origin, Commit, Initialize) free themselves in theon_donethey pass, not in the dock.
- Signals up, calls down. Static typing everywhere.
- UI scripts never call
OS.execute(). Never build shell strings from unchecked input. - Stale-result guards (latest-wins) for async diffs.
- Regular expressions go through
GitotRegex.compiled(pattern): one compiledRegExper pattern, built on first use.
Generated class docs are in docs/doctool. More internals: Implementation Details.
addons/gitot/
├── plugin.cfg # Plugin manifest (name, version, entry script)
├── gitot.gd # EditorPlugin entry point; lifecycle, wiring, main-screen tab registration
├── core/
│ ├── git_engine.gd # Command API + command_completed signal (per-call context); delegates execution to GitRunner
│ ├── git_runner.gd # Process execution: worker threads, timeouts, shell redirect, write lock (no git-domain knowledge)
│ ├── git_sync_orchestrator.gd # push → create-tag → push-tag state machine; plan_push() picks normal / force-confirm / blocked
│ ├── git_branch_entry.gd # Typed branch row (GitBranchParser output)
│ ├── git_status_entry.gd # Typed status row (path, status)
│ ├── git_commit_entry.gd # Typed history row
│ ├── git_stash_entry.gd # Typed stash row
│ ├── git_lfs_file.gd # Typed LFS file row (with_scope())
│ ├── git_ignore.gd # Default Godot .gitignore, created only when missing
│ ├── git_branch_parser.gd # Parses `git branch -a --format=...` (`GitBranchParser.FORMAT`) into local/remote branch entries
│ ├── git_status_parser.gd # Parses `git status --porcelain=v2`
│ ├── git_diff_parser.gd # Parses `git diff -U0/-U3` hunks + `--name-status` output
│ ├── git_log_parser.gd # Parses `git log` (custom \x1f-delimited) into commit entries
│ ├── git_stash_parser.gd # Parses `git stash list` (custom \x1f-delimited) into stash entries
│ ├── git_path.gd # Decodes git's quoted (escaped) paths to UTF-8; to_file_list() decodes name-list results
│ ├── git_remote.gd # Remote URL rules: owner/repo, browsable address, add_remote() whitelist
│ ├── git_ref.gd # Tag and branch name rules
│ ├── gitot_regex.gd # GitotRegex.compiled(pattern): one compiled RegEx per pattern
│ ├── git_format.gd # UNIT_SEP, the field separator shared by the `--format` strings and their parsers
│ ├── git_lfs.gd # GitLfs facade: state detection, track/untrack, pull, prune; typed signals
│ ├── git_lfs_parser.gd # Parses `git lfs ls-files --json` + LFS patterns from .gitattributes; merge_scopes(), summarize() stats
│ ├── github_auth.gd # PAT storage (user://gitot_auth.cfg, plaintext)
│ ├── github_api.gd # Authenticated HTTPRequest wrapper for GitHub REST API
│ ├── github_issue_parser.gd # Normalizes raw GitHub issue JSON (type/priority/labels/branch-name slug)
│ ├── gitot_repo_state.gd # Ahead / behind / upstream state of HEAD, `changed` signal
│ ├── gitot_settings.gd # GitotSettings; settings storage (user://gitot_settings.cfg)
│ └── gitot_logger.gd # GitotLogger; centralized print wrapper, capped history + UI listener
└── ui/
├── gitot_dock.tscn / gitot_dock.gd # Local Git dock UI shell (wiring, toolbar, refresh)
├── gitot_editor_sync.gd # EditorFileSystem / open scene / script refresh after git changed files
├── gitot_commit_flow.gd # Commit use case: commit / amend, amend confirmation, busy and amend wording of the commit area
├── gitot_push_flow.gd # Push use case: plan, confirm, tag input validation, hand-off to the orchestrator
├── gitot_working_diff.gd # Working-tree mode of the diff panel (gutter click / Refresh), stale-result guard
├── gitot_result_router.gd # Routes command_completed results to domain handlers; emits files_changed / file_restored / status_parsed / origin_added
├── gitot_branch_results.gd # Branch command results (list, switch, create, delete, current branch); emits head_moved / branches_parsed
├── gitot_sync_results.gd # Fetch, ahead/behind, push, pull and tag-push results; emits head_moved after a pull
├── gitot_messages.gd # Failure layout and network hint shared by the result handlers
├── gitot_repo_init.gd # Initialize repository button and result
├── gitot_remote_prompt.gd # Remote URL dialog for the first push
├── gitot_status_tree.gd # Staged/unstaged file trees: population, status letters/icons, staging, bulk actions, size guard
├── gitot_file_tooltip.gd # FileSystem dock hover tooltip: adds each file's git status (EditorResourceTooltipPlugin)
├── gitot_log_panel.gd # Commit history fold: Tree population, filters, commit_selected signal
├── gitot_stash_panel.gd # Shelf fold: stash list Tree, Stash/Pop/Drop, cap, drop confirm
├── gitot_ui.gd # Shared UI helpers: icons (incl. white), title-bar buttons, busy state, sync symbols/counts/tooltips, push tooltip
├── gitot_commit_files_list.gd # Changed-files ItemList for one commit; pure UI
├── gitot_commit_log_diff.gd # Commit-mode flow (history → file list → diff); latest-wins gate
├── gitot_branch_panel.gd # Branch list fold: Tree, switch/track on double-click, Fetch button, title-bar sync status
├── gitot_branch_creator.gd # Inline create-branch row (+ toggle), confirmation gate
├── gitot_branch_deleter.gd # Delete-branch / Delete-on-origin buttons and confirmations
├── gitot_status_panel.gd # Compact repo-state summary (owner/repo link, branch, scope)
├── gitot_diff_gutter.gd # Script editor gutter coloring + click-to-diff (hunk_clicked signal); teardown() hides the gutter
├── gitot_tag_panel.gd # Tag-versioning UI: toggles, version-tag formatting, tag resolution
├── gitot_settings_panel.gd # Settings panel UI; reads/writes GitotSettings directly
├── gitot_log_console.gd # Live console view backfilling GitotLogger.get_history(); owns the Info menu (Reflog, Repo size, Copy/Clear log)
├── github_issue_list.gd # Issue Tree: population, header-click sort, filter integration
├── github_issue_filter.gd # Type/Priority/Label dropdowns + AND-match rule
├── github_panel.tscn / github_panel.gd # GitHub Issues Tracker Board, main-screen tab, owns GithubApi
├── issue_detail.tscn / issue_detail.gd # Selected-issue detail: header, actions, branch creation, body
├── gitot_lfs_panel.tscn / gitot_lfs_panel.gd # "Gitot LFS" bottom panel: dashboard (state, stats, patterns, actions) + files tree, setup guide
├── gitot_diff_panel.tscn / gitot_diff_panel.gd # Bottom-dock full diff viewer; show_raw_diff() = size cap + parse for both modes
└── github_auth_dialog.tscn / github_auth_dialog.gd # PAT entry modal, opened on first use or 401