Git

Editora’s Git support shells out to your installed git, with no bundled library. It’s on by default; turn it off in Settings → Version Control → Git or with view.toggleGit. If git isn’t installed, the integration stays inert.

Git integration

  • The status bar shows the current branch with ahead/behind counts. Click it for a dropdown to switch or create branches, pull, fetch, and push. Outside a repo it reads “No VCS” and offers to clone or create one. While a merge, rebase, cherry-pick, or revert is in progress it names it (main · MERGING). A repository Git refuses to work in (for example “dubious ownership”) is reported with Git’s reason in the status bar and the Commit window.
  • Gutter change bars mark added and modified lines against HEAD; deleted lines show as a corner flag at the top of the line that follows them. Hover a bar for that hunk’s diff, or click it for a card with actions (see Changes in the editor). Editor tabs are tinted by their file’s Git status, and the minimap marks changed lines.
  • The Project tree marks files by Git status, IntelliJ-style: a single-letter prefix (M / A / D / R / U) and a color, added (green), modified (blue), deleted (gray), renamed (violet), untracked (olive), with changed folders tinted. The Commit window’s rows use the same letters and colors, so the two read identically. It updates as you edit, stage, commit, or switch branches.
  • The Commit tool window (M-4) groups staged, changed, and untracked files with stage, unstage, discard, and a commit box (Ctrl/Cmd+Enter to commit). See The Commit window.
  • A Git Log tool window (C-x v S-l), the active file’s Git history (Show Git History, git.fileHistory, C-x v l), blame annotations in a gutter column (toggle with git.toggleBlame), and stashes (git.stashes).

In a file’s Git history, double-click a commit or press Enter to open what that commit changed in the file. Compare with Working Tree in the row’s menu opens the editable comparison instead: the full diff viewer, including line, hunk, whole-file, Result, Undo, and Save controls. See Git history of one file. Revisions Editora records itself on every save are a separate feature, Local History.

ActionCommandDefault key
Commit (open the Commit window)git.commitC-x v v
Switch branch (dropdown)git.switchBranchC-x v b s
New branchgit.newBranchC-x v b c
Pullgit.pullC-x v S-=
Pushgit.pushC-x v S-p
Fetchgit.fetch(palette)
Next / previous change in the filegit.nextChange / git.previousChangeC-x v ] / C-x v [
Git Logtool.gitLogC-x v S-l
Show Git History (the active file’s commits)git.fileHistoryC-x v l
Toggle blame annotationsgit.toggleBlameC-x v g
Clone a repositorygit.clone(palette)
Create a repository in a foldergit.init(palette)
Refreshgit.refresh(palette)

The VCS menu keeps the daily actions at the top level (Commit, Commit and Push, Push, Pull, Fetch, Switch Branch, Git Log, and Continue / Skip / Abort) and groups the rest into submenus: Changes, Branches, Remotes & Worktrees, Tags, Stash, Patches, History & Blame, and Compare.

Cloning asks for a URL and a destination, then opens a file from the clone (its README if present) so Git activates without creating a project. The clone form also takes a branch (blank is the remote’s default), a shallow depth (blank is all history), and an option to clone submodules. The destination can start with ~ or be relative; missing parent folders are created, and an existing empty folder is accepted.

Branch switch, pull, and push reload unmodified open buffers whose files changed on disk. Branch switches, discard, and stash never silently replace a dirty open copy; deleted and edited buffers remain available for recovery. Git paths are passed literally, including names that look like options or contain unusual characters, and conflicted entries remain visible while a merge is unresolved. History mutations and refreshes also revalidate the active file and working-tree state before applying their result.

Editora uses the git on your PATH; Git: Set Git Command (git.setCommand) points it somewhere else, and a blank value goes back to the PATH one. Editora never asks for a password, a key passphrase, or a host-key confirmation, and Git commands never start an external editor. When a remote refuses to sign you in, the error says what to set up (a credential helper, an SSH agent, or a first connection from a terminal).

The Commit window

The Commit window (tool.commit, M-4) lists Staged, Changes, and Untracked files, each row with its added and removed line counts. Its header shows how many commits are waiting to be pushed or pulled, or that the branch has not been published yet.

  • Space stages or unstages the selected rows; on a group header it acts on the whole group. Group menus offer Stage All in Group, Unstage All (git.unstageAll), and Discard All Changes… (git.discardAll), which returns tracked files to the last commit and deletes untracked files after a confirmation.
  • Amend (git.commitAmend) makes the next commit replace the last one. Nothing needs to be staged to change only its message. If the commit is already on the remote, the window says that amending it will need a force push.
  • Commit and Push (git.commitAndPush) commits and then pushes the branch. A failed commit does not push.
  • Sign off adds a Signed-off-by line (git commit -s). The choice is remembered for the repository until Editora closes.
  • A length guide under the message shows the subject length and counts long body lines, following the 50/72 convention. It is advice only and never blocks a commit.
  • Recent Commit Messages… (git.commitMessageHistory) puts a message you committed earlier in this session back in the box. When the repository has a commit.template, the box starts from it and its comment lines are left out of the commit.
  • Undo Last Commit… (git.undoLastCommit) takes the last commit off the branch, keeps its changes staged, and puts its message back in the commit box (git reset --soft HEAD~1). It asks first, and warns when the commit is already on the remote. A merge commit or a branch’s first commit is not undone this way.

Ctrl/Cmd+Enter does nothing when nothing is staged or while a commit is running. The list keeps its selection, collapsed groups, and scroll position as the status updates.

Operations in progress and conflicts

A merge, rebase, cherry-pick, or revert that stops part-way is shown in the status bar and as a banner at the top of the Commit window, with Continue, Skip, and Abort.

ActionCommandDefault key
Continue once the conflicts are resolvedgit.continueOperation(palette)
Skip the commit a rebase, cherry-pick, or revert stopped atgit.skipOperation(palette)
Abort and go back to the state before itgit.abortOperation(palette)
Open the resolver for the active filemerge.resolve(palette)

Any Git command that stops on conflicts (pull, merge, rebase, revert, cherry-pick, stash pop, or a 3-way patch) opens the Commit window with the conflicted files in their own Conflicts group. Each has:

  • Resolve Conflicts…, which opens the three-way resolver. Applying a complete resolution saves the file and stages it, which clears it from the group.
  • Actions that keep one side whole. They are named for what the sides mean in the current operation: Accept Ours / Accept Theirs in a merge, Keep the Upstream Version / Keep My Commit’s Version in a rebase, and Accept the Commit’s Version in a cherry-pick or revert.
  • Mark Resolved, for a file you fixed by hand.

Committing is blocked while conflicts are unresolved. When a merge is ready to conclude, the commit box is prefilled with the message Git prepared.

Pulling and pushing

Pull mode (Settings → Version Control → Git, or git.setPullMode) decides how git.pull brings in the remote commits:

  • Fast-forward only (the default) never rewrites or merges anything. When the branch and its upstream have diverged, the pull offers Rebase or Merge for that one pull.
  • Rebase replays your local commits on top of the remote ones.
  • Merge joins the two histories with a merge commit.

git.pullRebase and git.pullMerge pull one way regardless of the setting. Rebase and merge pulls carry uncommitted changes across with --autostash and report what happened to them; if applying them back conflicts, they stay in the stash and the conflicts appear in the Commit window.

ActionCommandDefault key
Push the current branchgit.pushC-x v S-p
Push to another remote or under another branch namegit.pushTo(palette)
Force pushgit.pushForce(palette)
Push every local tag the remote lacksgit.pushTags(palette)

The first push of a branch publishes it to the push remote configured in Git (the branch’s pushRemote, then the repository’s pushDefault) or to the repository’s only remote. Force Push always uses --force-with-lease and asks first: it is refused if the remote branch has moved since your last fetch. A push rejected because the remote has commits you do not offers Pull, then Push, Force with Lease, or Cancel.

Automatic fetch

Fetch automatically (Settings → Version Control → Git, or git.toggleAutoFetch) fetches the active repository in the background so incoming commits show without asking. It is off by default; the interval is 10 minutes unless you change it (git.setAutoFetchInterval). The background fetch never prompts, and runs only in a trusted folder or in a repository you have fetched, pulled, or pushed in during the session.

Branches

The branch dropdown has a search field over three sections: Actions (New Branch, Pull, Fetch, Push, and the like), then Local branches with the current one first, then Remote branches, grouped by remote when there are several. It opens with the current branch selected. Clicking a row checks the branch out. A row’s ⋯ button, a right-click, or the Menu key opens its actions; the same actions are in the palette and under VCS ▸ Branches.

Each section folds to its header: click the header, or select it and press Enter, ← or →. A folded header shows how many rows it hides, and the choice is remembered with the workspace. Typing in the search field looks through every section, folded or not.

ActionCommand
New branch from any branch or tag, with or without switching to itgit.newBranchFrom
Check out a tag, branch, or commit by namegit.checkoutRevision
Rename a local branchgit.renameBranch
Merge a branch into the current onegit.mergeBranch
Rebase the current branch onto anothergit.rebaseOnto
Review the files that differ from the current branchgit.compareBranch
Set or unset the upstreamgit.setUpstream / git.unsetUpstream
Delete a local branchgit.deleteBranch
Delete a branch on its remotegit.deleteRemoteBranch

Deleting a branch with commits that are not merged into the current branch asks first and states how many there are. Deleting on the remote always asks. A local branch whose upstream was deleted is marked “(gone)”. Checking out a tag or a commit reports the detached HEAD.

Remotes and worktrees

Manage Remotes… (git.remotes) lists the repository’s remotes with their fetch and push URLs and can add, rename, re-point (Set URL), fetch, prune, and remove them. Fetch Remote… (git.fetchRemote) fetches one remote and prunes its deleted branches.

Manage Worktrees… (git.worktrees) lists the repository’s worktrees and can add one (for an existing branch or a new one; a relative folder is created beside the repository), open one in a new window, remove one, and prune entries whose folder is missing. Removing a worktree deletes its folder and keeps its branch and commits; one that holds modified or untracked files asks again before deleting them.

Tags

ActionCommand
New tag at the commit selected in the Git Log, or at HEADgit.tag.create
Check out a taggit.tag.checkout
Push one taggit.tag.push
Delete a taggit.tag.delete

The same actions are on a commit row’s context menu in the Git Log. A new tag with a message is annotated; leaving the message empty makes a lightweight tag. Deleting a tag removes it locally only.

Changes in the editor

The gutter marks are also the way to work on one change at a time, compared with HEAD.

ActionCommandDefault key
Go to the next / previous changegit.nextChange / git.previousChangeC-x v ] / C-x v [
Peek the change at the caretgit.peekChange(palette)
Revert the change at the caretgit.revertHunk(palette)
Stage the change at the caretgit.stageHunk(palette)
Stage / unstage the whole filegit.stageFile / git.unstageFile(palette)
Discard the file’s changesgit.discardFile(palette)

Next and previous wrap around at the ends of the file and report the position (“Change 2 of 5”). Clicking a change bar, or Peek Change at Caret, opens a card showing the old and new lines with Revert Hunk, Stage Hunk, Copy Old Text, Open Diff, and Previous / Next.

Revert Hunk puts the HEAD lines back into the buffer as an ordinary undoable edit; nothing is written to disk. Stage Hunk saves the file first and then stages only that change. Change bars and blame annotations follow unsaved insertions and deletions as you type.

Git Log

The Git Log (tool.gitLog, C-x v S-l) lists the current branch’s commits and loads more as you scroll, a page at a time, so it reaches the whole history (git.log.loadMore does the same from the keyboard).

  • All branches (git.log.toggleAllBranches) lists the commits of every branch, remote, and tag.
  • A commit graph is drawn beside the rows when the list is a plain walk of the history. It is hidden for a file history, a search result, and a filtered list.
  • The details area shows the selected commit’s full message, author, date, hash, parents, and refs, above the files it changed.
  • Enter on a commit (git.log.reviewCommit) opens everything it changed as one multi-file review. With two commits selected, Compare Selected Commits (git.log.compareSelected) reviews the difference between them.
  • A commit’s context menu has Copy Hash, Checkout, New Branch from Here…, New Tag…, Revert Commit, Cherry-Pick, Reset Current Branch to Here, and Create Patch…. The matching Git Log: … palette commands act on the commit selected in the visible log; when the log is hidden they open it and ask for a commit.
  • File history follows the file across renames.

Git history of one file

Show Git History (git.fileHistory; C-x v l, or Ctrl+Alt+Shift+H in the other keymaps) lists the commits that changed the active file, in the Git Log tool window under a Git history: name chip. It is also in a tab’s menu, the Project tree, and VCS ▸ History & Blame.

  • Enter or a double-click on a commit opens what it changed in that file. The row’s menu starts with Show Diff and Compare with Working Tree, and still has Review Commit for the whole commit.
  • The chip’s ✕, or Escape in the commit list, returns to the branch log.
  • Load More continues through the file’s whole history, a page of 200 commits at a time.
  • A search finds commits from before a rename too. A path: term is ignored in a file history, and the status bar says so.
  • A file that is untracked or not yet committed says it has no commits, and a shallow clone says under its last row that older history is not available locally.
  • In the list of files under the commit, Enter compares that revision with the working file. When the file no longer exists in the working tree, it shows the commit’s change instead.

Typing in the filter box narrows the commits already loaded. Pressing Enter there (or git.log.search) searches the whole history:

TermMeaning
any other wordmessage text; every word must match
author:nameauthor name or e-mail contains name
content:textcommits that add or remove text
since:date, until:dateanything Git reads as a date
path:globcommits touching a matching path, from the repository root

Terms are separated by blanks, double quotes keep blanks inside one term, and matching ignores case. A running search is cancelled when you replace or clear it.

Reset (Soft, Mixed, or Hard) states how many commits leave the branch and how many of them are not on the upstream, and asks before stranding any. Reverting a merge commit asks which parent is the mainline.

Blame

git.toggleBlame (C-x v g) shows each line’s last commit, author and date, in a gutter column. git.blameShowCommit opens the diff of the commit that last changed the caret line.

  • Annotate Previous Revision (git.blamePreviousRevision) opens the file as it was before the commit the caret line is blamed on, annotated in turn, so you can walk a line back through history.
  • Ignore Whitespace Changes (git.blame.ignoreWhitespace) looks through commits that only changed whitespace (git blame -w).
  • Detect Moved and Copied Lines (git.blame.detectMoves) follows lines moved or copied within and between files (git blame -M -C).
  • A .git-blame-ignore-revs file at the repository root is used automatically.

The two toggles apply to the window they are set in.

Stashes

Stash Changes… (git.stash) takes an optional message and three options: include untracked files, stash the staged changes only (Git 2.35 or later), and keep the staged changes in the index.

Stashes… (git.stashes) lists every stash with the files it holds. Enter shows a stash’s changes as a review, and each stash can be applied, popped, dropped, turned into a branch, or have its name copied. git.stashPop applies and removes the latest stash, git.unstash applies one you pick, and git.stashDrop deletes one.

A stash that applies with conflicts is kept, and the conflicted files appear in the Commit window. A stash that would overwrite local changes is not applied.

Patches

Create Patch… (git.createPatch) writes the staged changes, the unstaged changes, or a commit you pick as a patch, to a file or to a new untitled buffer. Create Patch… on a Git Log row (git.log.createPatch) does the same for that commit.

Apply Patch… (git.applyPatch) applies a .patch/.diff file, or the active buffer if it is a patch, to the working tree or to the index. The patch is checked first: one that does not fit changes nothing, shows Git’s message, and offers Try 3-Way Merge, which applies what fits and leaves conflict markers where it does not. Those conflicts appear in the Commit window like any others.

To read a patch before applying it, see Diff & merge.

What runs automatically

Some Git commands run without you asking: status, the gutter diff, log, blame and file-content lookups happen as you open files and switch tabs. Editora runs those background reads so that a repository’s own configuration cannot start a program through them. core.fsmonitor and hooks are overridden, external diff and textconv drivers are switched off, and Git never waits on a terminal prompt. A partial clone is also told not to fetch missing objects on demand; that needs Git 2.45 or newer (or a 2.39.4–2.44.1 maintenance release), and older versions ignore it.

One thing is not covered: filter drivers selected through .gitattributes (Git LFS, for example) still run when Git has to re-hash a modified file.

Commands you start yourself (commit, checkout, pull, push and the rest) are not restricted, so your hooks run as they do in a terminal. A revision name that starts with - is refused rather than passed to Git, where it would be read as an option.

None of the automatic reads contact a remote. The only network command Editora starts on its own is the optional automatic fetch, which is off by default.

Seeing what it ran

The Output console (tool.buildOutput) has a Git tab holding a transcript of what Editora ran on your behalf: the command line, its output, and its exit code and duration.

It logs the commands you asked for: commit, push, pull, fetch, checkout, stash and clone. It leaves out the status and diff reads it re-runs on every tab switch, focus change and save, which would bury them.

Clone, fetch, pull, and push open the Git tab as soon as they start and show the command running: the git command line, then Git’s own progress (counting, receiving, resolving, writing) updating in place, then the exit line. While one runs, the tab’s Stop button or git.cancel cancels it. A command that fails also brings the tab forward. A local command that succeeds does not, so a Git Log action leaves the log in view and the transcript is there when you open the window.

After a pull, the transcript lists the files it changed. Clicking a file’s change graph (4 ++--) opens a diff of that file between the commit you were on and the one the pull brought; clicking the file name opens the file.

For comparing files and resolving merge conflicts, see Diff & merge. For pull requests, reviews, and CI runs, see GitHub.