Skip to content

Releases: VictorQuilgars/git-vertex

v1.39.0

Choose a tag to compare

@VictorQuilgars VictorQuilgars released this 23 Sep 12:18

Security

  • API keys were stored unencrypted, and are not any more. Regenerate them. Credentials in settings.json go through the system's protected storage — the Keychain, DPAPI, the keyring — so a file copied to another machine yields nothing. Which settings are credentials was a list written by hand when there were four providers, and #169 then made adding a cloud a catalog line: nobody edited the second list. So Mistral, DeepSeek, xAI and OpenRouter have been writing their API key to settings.json in clear since v1.32.0, and handing it to the window unmasked. The list is now derived from the catalog itself, so a provider is sealed by arriving rather than by being remembered, and a test walks the catalog and fails on any key that is not a secret. Sealing had always happened on write, which was correct and not enough — nothing forces a write, which is how this lasted six releases — so the app now seals at startup, before the window can ask for anything. ⚠️ That fixes the file and only the file. A settings.json rewritten today says nothing about the copies a backup, a synced folder or a passing script took while it was readable, and the app can reach none of them: if you had a key on one of those four providers, regenerate it at the provider. The app says so itself — the bell carries one notification naming the providers it found in clear.

Added

  • A conflicting pull request says which files, and offers the way out. The forge answers would this merge with a boolean, and the request's pane rendered it and stopped: Conflicts with the base, one line, naming nothing and offering nothing — the one place in the app that said something was wrong and gave neither the what nor the how. The names were always one merge-tree away, and the branch card beside it already showed them for a branch. The pane now lists the conflicted paths, with the count on the row itself, for a request whose head is in a fork as much as one whose head is a branch here: both sides are read from the remote — a local branch of the base's name may be behind, and a prediction against a stale base is a prediction about nothing — and no ref is written, the two commits being read from FETCH_HEAD rather than fetched into a branch. Under the list, the two ways out, with what each costs: Update from base, which rewrites nothing, then Rebase onto base — offered on the checked-out head branch and nowhere else, since both rewrite the branch you are standing on, and a fork's head is not a branch of this repository at all. Either lands in the conflicts panel the app already has, Resolve all with AI included, and nothing is committed for you. A prediction that could not run — a git below 2.38, a head the remote will not give — reads as could not tell, never as no files. (#305)
  • A branch says which of its commits the target already has, under another hash. A branch merged on the forge with rebase or squash does not put its commits on the target: it puts copies there, same patch, new hash. A branch that was stacked on that one still carries the originals — and then every changelog-shaped file conflicts, over a change that is already in, twice. The branch's card now says so — 2 of these commits are already in main, under another hash, with each one's sha and subject — and offers the one step that fixes it, Rebase onto main to drop them. The answer is git cherry, which is patch-id underneath and the same test the rebase itself uses to drop them: what is named is exactly what the rebase would remove, not a guess from subjects or dates. (#307)
  • A worktree row carries its branch's menu. The row knew which branch the worktree held and offered nothing about it: syncing that branch, giving it an upstream, renaming it, comparing it or opening its pull request meant going back to Branches and finding it again. A right-click on a worktree now offers the branch's own menu, after the worktree's own entries — push, upstream, merge, rebase, rename, delete, compare, the pull request, graph display — built by the same builder the branch row uses, so an action sits in the same place whichever row was clicked. What the row above it already answers is left out: its Open is opening that worktree, and git refuses both a switch to a branch another worktree holds and a second worktree for one. A detached worktree is on no branch, and keeps its worktree entries alone. (#286)

Changed

  • What this repository keeps has a page, and the side bar has its room back. Keep filed a search or a comparison under Kept, a block between the working changes and the branches — a column 260 px wide, where a kept search can only ever be a name, and where an empty list still spent a heading and a sentence of explanation above LOCAL. A kept search is not a name: it is a question, and the commits that answered it. It is a page now — Memory, from the bookmark beside the bell, and an editor tab from the panel's toolbar: the kept things on the left, and on the right what the one you picked actually holds — the query as its operators, when it was kept, and its commits, each with its author and its date. From there: show them in the graph, put the search back in the field, compare the oldest with the newest, copy the hashes. Ask again is what makes keeping one worth anything: the same query put to git, over the whole history, where the kept answer was a photograph of a live filter over the page the graph happened to hold that day — the commits it did not have are marked new, and Keep this answer instead makes today's answer the one it holds. A commit the repository no longer has is counted, not missed: 1 kept commit is no longer in this repository is what a rebase since looks like. A search the model answered is asked of the model again, not of git. A kept comparison lists its files with the ones you had ticked as reviewed, so 3 of 12 files reviewed is on the page rather than inside the comparison. And the kept searches are listed under the search field itself, in the panel that opens when it takes the focus: a search one kept is a search one means to run again, and that is where searches are run.
  • The search field asks the model without a button to find first. Searching in words was behind a ✨ at the field's far right: you had to press it before typing, and nothing said it was there. Meanwhile the panel that opens the moment the field takes the focus showed operators and nothing else — so the field announced, on the first click and to everybody, that author: and file: were all it could do. The panel now opens on Ask in plain language and the operators come under it: the row echoes the words you have typed — Ask the model for "the commits that broke the build" — and Enter in the field sends them, which is a key that meant nothing here, the filter being live as it is typed. The placeholder says both. There is no mode to arm any more: the model's answer being on screen is a state, drawn as the field's iris ring and a mark beside the count rather than a switch somebody has to remember throwing, and one keystroke in the query leaves it — back to the live filter, which is the feedback typing wants. A query made of operators alone sends nothing: that filter already holds. The ✨ goes with it: the icon set has carried an ai mark for as long as the app has had AI in it, and the search field was the one place a glyph stood in for it. The VS Code panel has no model behind its field and gets no such row, rather than a row that answers not-implemented.

Fixed

  • A search stays with the repository it was typed in. Everything else about a repository came back with its tab — its page, its selection, how far it had been loaded — but the search field was state of the window: switching to another repository left the words typed in the one you had just left sitting in the field, the new repository's graph opened greyed out underneath them, and the count read 0 about commits nobody had searched for. Worse in the two cases that are not text at all: the model's answer and the show these commits set of an AI reading both kept lighting rows in a repository they had nothing to say about. The search — the query, the diff-search toggle, the model's answer and the noted set — is kept per repository now and comes back with its tab, which is what the tab already promises about everything else; a repository whose tab is closed is forgotten with it. The VS Code panel has cleared the search on a switch since it learnt to show more than one repository, and keeps doing exactly that: it has no tabs to come back to.
  • The graph no longer draws commits it cannot name. A page was collected with --all, which is every ref under refs/, while a chip can only ever say branch, remote branch, tag or stash — which is exactly the set git's own decoration covers. So for a ref outside them %D came back empty, and its commits became rows belonging to nothing: absent from the side bar, unhideable (visibility is stated in those same four families), and refused by every action, all of which are defined against the branch you are on. Drop answered Commit not found about a commit whose hash was on the row that had just been right-clicked. git filter-branch leaves such a ref in refs/original/, and a branch squash-merged on the forge then kept its originals in the graph for good; an editor's refs/prefetch/, a refs/notes/ commit and a bisect's refs/bisect/ did the same. The searches were asked with the same --all and are asked with the same families now, so a file: hit, a diff search hit and a name in the contributors list are all things the graph has rows for. The page is collected from the four families now, and git still decides reachability inside each ...
Read more

Git Vertex VS Code Extension v1.37.0

Choose a tag to compare

@github-actions github-actions released this 23 Sep 12:15

Git Vertex VS Code Extension v1.37.0

Security

  • API keys and GitHub tokens were stored unencrypted, and are not any more. Regenerate them. The panel kept its settings in VS Code's globalState, which is not encrypted on disk — so every AI provider key, and the personal access token from Set GitHub token, was readable by anything that could read the profile, and settingsGetAll handed the lot to the webview besides. They live in the editor's secret storage now, the keychain-backed store the extension already used for OAuth tokens and nothing else; globalState keeps a mask where a credential was, and the webview is given masks. What counts as a credential is the desktop's own list, shared, so the two products cannot drift on the question. A migration moves whatever is already in clear, once, when the extension starts. ⚠️ Moving them protects the store from here on and nothing before it: a profile backup or Settings Sync may still hold a readable copy, so regenerate your keys and your token. The extension says so on the first start after the update.

Added

  • A conflicting pull request says which files, and offers the way out. The forge answers would this merge with a boolean, and the request's pane rendered it and stopped: Conflicts with the base, one line, naming nothing and offering nothing — the one place in the app that said something was wrong and gave neither the what nor the how. The names were always one merge-tree away, and the branch card beside it already showed them for a branch. The pane now lists the conflicted paths, with the count on the row itself, for a request whose head is in a fork as much as one whose head is a branch here: both sides are read from the remote — a local branch of the base's name may be behind, and a prediction against a stale base is a prediction about nothing — and no ref is written, the two commits being read from FETCH_HEAD rather than fetched into a branch. Under the list, the two ways out, with what each costs: Update from base, which rewrites nothing, then Rebase onto base — offered on the checked-out head branch and nowhere else, since both rewrite the branch you are standing on, and a fork's head is not a branch of this repository at all. Either lands in the conflicts panel the app already has, Resolve all with AI included, and nothing is committed for you. A prediction that could not run — a git below 2.38, a head the remote will not give — reads as could not tell, never as no files. (#305)
  • A branch says which of its commits the target already has, under another hash. A branch merged on the forge with rebase or squash does not put its commits on the target: it puts copies there, same patch, new hash. A branch that was stacked on that one still carries the originals — and then every changelog-shaped file conflicts, over a change that is already in, twice. The branch's card now says so — 2 of these commits are already in main, under another hash, with each one's sha and subject — and offers the one step that fixes it, Rebase onto main to drop them. The answer is git cherry, which is patch-id underneath and the same test the rebase itself uses to drop them: what is named is exactly what the rebase would remove, not a guess from subjects or dates. (#307)
  • A worktree row carries its branch's menu. The row knew which branch the worktree held and offered nothing about it: syncing that branch, giving it an upstream, renaming it, comparing it or opening its pull request meant going back to Branches and finding it again. A right-click on a worktree now offers the branch's own menu, after the worktree's own entries — push, upstream, merge, rebase, rename, delete, compare, the pull request, graph display — built by the same builder the branch row uses, so an action sits in the same place whichever row was clicked. What the row above it already answers is left out: its Open is opening that worktree, and git refuses both a switch to a branch another worktree holds and a second worktree for one. A detached worktree is on no branch, and keeps its worktree entries alone. (#286)

Changed

  • What this repository keeps has a page, and the side bar has its room back. Keep filed a search or a comparison under Kept, a block between the working changes and the branches — a column 260 px wide, where a kept search can only ever be a name, and where an empty list still spent a heading and a sentence of explanation above LOCAL. A kept search is not a name: it is a question, and the commits that answered it. It is a page now — Memory, from the bookmark beside the bell, and an editor tab from the panel's toolbar: the kept things on the left, and on the right what the one you picked actually holds — the query as its operators, when it was kept, and its commits, each with its author and its date. From there: show them in the graph, put the search back in the field, compare the oldest with the newest, copy the hashes. Ask again is what makes keeping one worth anything: the same query put to git, over the whole history, where the kept answer was a photograph of a live filter over the page the graph happened to hold that day — the commits it did not have are marked new, and Keep this answer instead makes today's answer the one it holds. A commit the repository no longer has is counted, not missed: 1 kept commit is no longer in this repository is what a rebase since looks like. A search the model answered is asked of the model again, not of git. A kept comparison lists its files with the ones you had ticked as reviewed, so 3 of 12 files reviewed is on the page rather than inside the comparison. And the kept searches are listed under the search field itself, in the panel that opens when it takes the focus: a search one kept is a search one means to run again, and that is where searches are run.

Fixed

  • The graph no longer draws commits it cannot name. A page was collected with --all, which is every ref under refs/, while a chip can only ever say branch, remote branch, tag or stash — which is exactly the set git's own decoration covers. So for a ref outside them %D came back empty, and its commits became rows belonging to nothing: absent from the side bar, unhideable (visibility is stated in those same four families), and refused by every action, all of which are defined against the branch you are on. Drop answered Commit not found about a commit whose hash was on the row that had just been right-clicked. git filter-branch leaves such a ref in refs/original/, and a branch squash-merged on the forge then kept its originals in the graph for good; an editor's refs/prefetch/, a refs/notes/ commit and a bisect's refs/bisect/ did the same. The searches were asked with the same --all and are asked with the same families now, so a file: hit, a diff search hit and a name in the contributors list are all things the graph has rows for. The page is collected from the four families now, and git still decides reachability inside each — hiding is still tips taken away, not a list of the survivors. The one thing --all gave that a collector does not is that it examines every working tree, so the HEAD of each other one is added back: a worktree's side bar row goes to its HEAD, and a detached one would have sent the graph somewhere it had no row for. That list costs a process, so it is only asked for when there are linked working trees at all — a question the disk answers in microseconds, and the answer is no for most repositories.
  • A rewrite says which branch, instead of saying the commit does not exist. Drop, Move and the rest are one rebase of the checked-out branch, so the commits they can act on are the ones that branch's history holds — and the graph draws every branch, so asking this of a commit on another one is an ordinary mistake to make. Two different states wore one sentence, and the wrong one: Commit not found, about a commit with its hash and its subject on screen. It now reads 4641c8d is not on "main" — rewriting can only remove commits from the branch you are on, and No such commit is said only about a commit git confirms there is none of, which is asked on the failure path alone.
  • A file tree no longer starts against the panel's edge. The depth of a row was written straight into its left padding, which replaces the row's own gutter rather than adding to it. Every level below the first had an indent wide enough to stand in for the missing gutter, so only the top one showed it: a top-level folder's disclosure triangle sat at 0, hard against the panel's edge, under a filter field inset from it — while the flat reading of the very same files, one click away on the same bar, started a gutter in, so the toggle shifted every row sideways. The indent is added to the gutter now, and the gutter is the left padding of the list that tree replaces, in the same spacing token — so the two readings line up and both follow the density. All three trees carried it, in both products: the commit's files, the working changes in the right panel, and the panel's own staging list.
  • The search field's panel no longer runs off the right of the window. It is as wide as what is in it, up to a cap, and it hung from the field's left edge unless it would overflow — measured once, as it opened. On an empty field it is narrow and fits; the moment something long went into it, it grew past the window and took the operators' examples with it, off the screen. It is measured after every change now, and still flips to the field's right edge once and once only, which is what keeps it from oscillating between the two sides.
  • The upstream picker no longer offers the remote itself. origin/HEAD is a symbolic ref to the remote's default...
Read more

v1.38.0

Choose a tag to compare

@VictorQuilgars VictorQuilgars released this 20 Sep 15:21
6d39d9c

Added

  • A branch, a remote branch or a tag opens its card from the side bar. The card — what the branch is, where it stands against its upstream, whether it merges cleanly, its next steps — could only be opened by clicking the chip on its tip's graph row, which meant finding that row first. Every one of those rows now leads with a card button, before the acts: reading comes before acting. It opens exactly what the chip opens, and in the order the card needs — the tip is selected first, then the card opens, because a card whose reference is not the selected commit closes itself on the next render. A tip that is not on the page yet is reached the way everything else reaches one. (#274)
  • A pull request can be checked out, opened in a worktree and read as code — a fork's included. Its row and its sheet offered View, Copy link and Open on GitHub: a request whose head was a branch of this repository could be checked out from Branches › REMOTE once you had worked out which remote branch it was, and a request from a fork could not be checked out at all. Every request's head is fetched from refs/pull/<n>/head, which GitHub publishes whatever repository the head lives in, into a local pr/<n> — never forced, so a pr/<n> you have committed on is refused with its reason rather than quietly rewritten. From there: Switch to its Branch, Open in a New Worktree, View Changes — the files and diffs from its base to its head, the base...head the request itself shows — and Compare Base and Head, the two trees as they stand. Reading the changes fetches and stops there: the objects are what a diff needs, and switching branches to read one is how a review costs a stash. The base is read from the remote, not from a local branch of that name which may be behind. The sheet carries the same three as buttons beside its link. (#290)
  • A worktree row says where it stands, and does what a folder can do. It showed a path, a branch and whether it was the main one; locked was read from git and never used. Each row now carries what it is — active for the one this window is showing, a lock with the reason git was given, a dot when it holds uncommitted work, its branch's ↑ahead ↓behind, and a mark when its folder is gone and git will drop it on the next prune. From the row: Open Terminal Here, Reveal in File Manager, Lock / Unlock with an optional reason, and Copy Working Changes to… another worktree — which stashes here and applies there, and keeps the stash whether or not the apply lands, because dropping the one copy of somebody's uncommitted work when the second half of a two-step operation fails is not a risk to take on their behalf. A branch checked out in another worktree offered Switch, which git refuses: its row now offers Open its worktree "review", and any branch can be given Create a Worktree for "x"… without typing its name. The worktree list is one shared parse now, where it had been written out twice. (#285)
  • A stash is a commit, and its row treats it as one — every stash, not just the newest. Only stash@{0} ever had a graph row, so an older stash could not be compared, selected or copied at all. Each row now offers Compare with HEAD, Compare with Working Tree and Select for Compare, and a Copy submenu with its full sha, its message and its patch — each resolved from the stash's own ref, so stash@{3} is reached exactly like stash@{0}. Preview contents is called Show Changes, which is what it does. (#287)
  • A branch is brought up to date, given an upstream of your choosing, and tidied — without switching to it. Pull was offered on the checked-out branch alone: bringing a second branch forward meant switching to it, pulling, and switching back. Pull "x" from its upstream now fast-forwards any local branch from where it is, and refuses with the reason rather than a bare failure — diverged from origin/x (1 ahead, 1 behind) — rebase or merge it, tracks no branch, already up to date, each of which calls for something different. Change Upstream… points a branch at any remote branch, listed for you: Set Upstream only ever set <default remote>/<same name>, which was the one upstream it could give. Rebase onto its Upstream and Squash Fixups sit on the branch you are standing on, because both rewrite its commits — and the autosquash rebases onto the fork point, never onto the upstream itself, so the fixup! commits fold in and the branch does not quietly move onto whatever the remote has grown since; with nothing to fold it refuses, because a rebase would rewrite every hash for nothing. The operations live in the shared git core, so the panel and the desktop give the same answers. (#280)
  • A branch row offers what its tip commit offers. Creating a branch, a tag or a worktree from that branch, resetting the current branch to it, copying its sha or its message, comparing it with the working tree or with something selected earlier — all of it existed on the graph row the branch happens to point at, and the side bar's + always branched from HEAD. The branch's own row now carries them, in the menu's own places: the copies in Copy, the comparisons in Compare, one of each rather than two. Resetting is not offered on the branch you are already on, and a comparison with a commit already selected is greyed out against itself, exactly as on the graph. (#281)
  • A remote branch can be merged, rebased onto and compared from its own row. Branches › REMOTE offered a checkout and a delete: merging origin/release into what you are on meant creating a local branch for it first. Its row now offers Merge into , Rebase onto this and Compare, and Hide Remote "origin" from Graph — which was on the Remotes row alone, a view away from the branch that made you want it. (#282)
  • Every side bar row does its commonest act on the row itself. Only a branch row showed anything under the pointer, and what it showed was the whole menu behind a kebab: the stash, tag, remote and worktree rows were reachable by right-click alone. Each row now carries two or three icons for what its own state calls for — a branch three commits behind offers Pull, one that is ahead offers Push, one the remote has never seen offers Publish, and one level with its upstream offers no sync at all, because an icon that would do nothing is worse than no icon; a branch whose upstream is gone offers none either, since there is nothing left to sync with. Beside it, Switch on any branch that is not the one you are on, and on a tag; Apply, Pop and Drop on a stash; Fetch and Open on a remote; Open on a worktree that is not the one on screen. They are real buttons at every moment, so the keyboard reaches them — tab into a row and its acts appear — and on a touch screen, which has no hover to discover them with, they are simply there. The full menu stays behind the kebab: nothing moved out of it. (#274)
  • One click on a side bar row takes the graph to it. A click on a branch did nothing, a tag answered only a double-click, and a worktree row was a no-op — the only way to a reference's commit was the graph's own / finder. A single click on a branch, a tag, a stash or a worktree now selects its commit in the graph and scrolls to it, growing the page when the commit is not loaded, the way the finder reaches a tip three pages down; a worktree row goes to its HEAD, and the one this window is open on goes to the working changes, which are the only ones this graph can show. The double-click keeps every meaning it had — switch, land on a branch, open the stash — and takes back the reveal the first press had armed. (#275)
  • The filter field narrows whatever list is on screen, and a list of paths can be a tree. Only the branches had a filter: a repository with two hundred tags was read by scrolling. The field is above every list view now — tags, stashes, remotes, worktrees — saying which one it is narrowing, and matching a stash by what it says and a worktree by its folder or its branch. Beside the section's count, a list / tree toggle wherever the names hold slashes: the branches can be flattened, the tags can be a tree, and the choice is kept per view on this machine. A filter still flattens whatever the choice was — a tree that stays folded while you type reads as an empty section — and a list with no slash in it is not offered a toggle at all. (#276)
  • A search or a comparison can be kept, named, and found again after a restart. A query built out of author:, file: and the rest was gone the moment the field was cleared, and a comparison was gone with the view. Keep — beside the search field, and on the comparison's header — names what is on screen and files it under Kept in the side bar: a click puts it back, the pencil renames it, the cross drops it. A kept comparison remembers which of its files you had ticked as reviewed, and the tick survives the restart with it. Everything is kept per repository and outside the renderer — in the settings both hosts already persist — so a VS Code tool tab, whose storage the overview webview does not share, finds the same list. (#256)
  • Pull requests, grouped by what they need from you. The view grouped by account — whose is it. A switch above the list adds the other reading, By what they need, and it is remembered: Current Branch, Needs Your Review, Changes Requested, Ready to Merge, Blocked, Waiting for Review, Draft, Other — each with its count, the rows keeping their actions, and every open request in exactly one group: the first rule that holds decides, so a request approved with red checks is Blocked, not Ready, and a draft asks nothing of anybody yet. What a list row does not carry — the review decision, the state of the checks ...
Read more

Git Vertex VS Code Extension v1.36.0

Choose a tag to compare

@github-actions github-actions released this 20 Sep 15:22
6d39d9c

Git Vertex VS Code Extension v1.36.0

Added

  • A branch, a remote branch or a tag opens its card from the side bar. The card — what the branch is, where it stands against its upstream, whether it merges cleanly, its next steps — could only be opened by clicking the chip on its tip's graph row, which meant finding that row first. Every one of those rows now leads with a card button, before the acts: reading comes before acting. It opens exactly what the chip opens, and in the order the card needs — the tip is selected first, then the card opens, because a card whose reference is not the selected commit closes itself on the next render. A tip that is not on the page yet is reached the way everything else reaches one. (#274)
  • A pull request can be checked out, opened in a worktree and read as code — a fork's included. Its row and its sheet offered View, Copy link and Open on GitHub: a request whose head was a branch of this repository could be checked out from Branches › REMOTE once you had worked out which remote branch it was, and a request from a fork could not be checked out at all. Every request's head is fetched from refs/pull/<n>/head, which GitHub publishes whatever repository the head lives in, into a local pr/<n> — never forced, so a pr/<n> you have committed on is refused with its reason rather than quietly rewritten. From there: Switch to its Branch, Open in a New Worktree, View Changes — the files and diffs from its base to its head, the base...head the request itself shows — and Compare Base and Head, the two trees as they stand. Reading the changes fetches and stops there: the objects are what a diff needs, and switching branches to read one is how a review costs a stash. The base is read from the remote, not from a local branch of that name which may be behind. The sheet carries the same three as buttons beside its link. (#290)
  • A worktree row says where it stands, and does what a folder can do. It showed a path, a branch and whether it was the main one; locked was read from git and never used. Each row now carries what it is — active for the one this window is showing, a lock with the reason git was given, a dot when it holds uncommitted work, its branch's ↑ahead ↓behind, and a mark when its folder is gone and git will drop it on the next prune. From the row: Open Terminal Here, Reveal in File Manager, Lock / Unlock with an optional reason, and Copy Working Changes to… another worktree — which stashes here and applies there, and keeps the stash whether or not the apply lands, because dropping the one copy of somebody's uncommitted work when the second half of a two-step operation fails is not a risk to take on their behalf. A branch checked out in another worktree offered Switch, which git refuses: its row now offers Open its worktree "review", and any branch can be given Create a Worktree for "x"… without typing its name. The worktree list is one shared parse now, where it had been written out twice. (#285)
  • A stash is a commit, and its row treats it as one — every stash, not just the newest. Only stash@{0} ever had a graph row, so an older stash could not be compared, selected or copied at all. Each row now offers Compare with HEAD, Compare with Working Tree and Select for Compare, and a Copy submenu with its full sha, its message and its patch — each resolved from the stash's own ref, so stash@{3} is reached exactly like stash@{0}. Preview contents is called Show Changes, which is what it does. (#287)
  • A branch is brought up to date, given an upstream of your choosing, and tidied — without switching to it. Pull was offered on the checked-out branch alone: bringing a second branch forward meant switching to it, pulling, and switching back. Pull "x" from its upstream now fast-forwards any local branch from where it is, and refuses with the reason rather than a bare failure — diverged from origin/x (1 ahead, 1 behind) — rebase or merge it, tracks no branch, already up to date, each of which calls for something different. Change Upstream… points a branch at any remote branch, listed for you: Set Upstream only ever set <default remote>/<same name>, which was the one upstream it could give. Rebase onto its Upstream and Squash Fixups sit on the branch you are standing on, because both rewrite its commits — and the autosquash rebases onto the fork point, never onto the upstream itself, so the fixup! commits fold in and the branch does not quietly move onto whatever the remote has grown since; with nothing to fold it refuses, because a rebase would rewrite every hash for nothing. The operations live in the shared git core, so the panel and the desktop give the same answers. (#280)
  • A branch row offers what its tip commit offers. Creating a branch, a tag or a worktree from that branch, resetting the current branch to it, copying its sha or its message, comparing it with the working tree or with something selected earlier — all of it existed on the graph row the branch happens to point at, and the side bar's + always branched from HEAD. The branch's own row now carries them, in the menu's own places: the copies in Copy, the comparisons in Compare, one of each rather than two. Resetting is not offered on the branch you are already on, and a comparison with a commit already selected is greyed out against itself, exactly as on the graph. (#281)
  • A remote branch can be merged, rebased onto and compared from its own row. Branches › REMOTE offered a checkout and a delete: merging origin/release into what you are on meant creating a local branch for it first. Its row now offers Merge into , Rebase onto this and Compare, and Hide Remote "origin" from Graph — which was on the Remotes row alone, a view away from the branch that made you want it. (#282)
  • Every side bar row does its commonest act on the row itself. Only a branch row showed anything under the pointer, and what it showed was the whole menu behind a kebab: the stash, tag, remote and worktree rows were reachable by right-click alone. Each row now carries two or three icons for what its own state calls for — a branch three commits behind offers Pull, one that is ahead offers Push, one the remote has never seen offers Publish, and one level with its upstream offers no sync at all, because an icon that would do nothing is worse than no icon; a branch whose upstream is gone offers none either, since there is nothing left to sync with. Beside it, Switch on any branch that is not the one you are on, and on a tag; Apply, Pop and Drop on a stash; Fetch and Open on a remote; Open on a worktree that is not the one on screen. They are real buttons at every moment, so the keyboard reaches them — tab into a row and its acts appear — and on a touch screen, which has no hover to discover them with, they are simply there. The full menu stays behind the kebab: nothing moved out of it. (#274)
  • One click on a side bar row takes the graph to it. A click on a branch did nothing, a tag answered only a double-click, and a worktree row was a no-op — the only way to a reference's commit was the graph's own / finder. A single click on a branch, a tag, a stash or a worktree now selects its commit in the graph and scrolls to it, growing the page when the commit is not loaded, the way the finder reaches a tip three pages down; a worktree row goes to its HEAD, and the one this window is open on goes to the working changes, which are the only ones this graph can show. The double-click keeps every meaning it had — switch, land on a branch, open the stash — and takes back the reveal the first press had armed. (#275)
  • The filter field narrows whatever list is on screen, and a list of paths can be a tree. Only the branches had a filter: a repository with two hundred tags was read by scrolling. The field is above every list view now — tags, stashes, remotes, worktrees — saying which one it is narrowing, and matching a stash by what it says and a worktree by its folder or its branch. Beside the section's count, a list / tree toggle wherever the names hold slashes: the branches can be flattened, the tags can be a tree, and the choice is kept per view on this machine. A filter still flattens whatever the choice was — a tree that stays folded while you type reads as an empty section — and a list with no slash in it is not offered a toggle at all. (#276)
  • File blame is one label per run of lines, with the author's face, and the cursor's commit lit. Every annotated line carried its own full label, so ten lines from one commit were ten repetitions of the same sentence. A run of consecutive lines from the same commit is labelled once now, the rest of the run wearing a thin continuation mark — and a gap in the blame breaks the run, because a partial answer must never suggest shared authorship. The label carries the author's avatar, their initials when no image can be had. Moving the cursor lights every line that commit wrote, the runs elsewhere in the file included, so what one commit touched is read at a glance. The age heatmap and the hover actions are untouched, and each of the three is a setting — gitVertex.blame.file.groupRuns, .avatars, .highlightCommit — on by default. (#254)
  • A search or a comparison can be kept, named, and found again after a restart. A query built out of author:, file: and the rest was gone the moment the field was cleared, and a comparison was gone with the view. Keep — beside the search field, and on the comparison's header — names what is on screen and files it under Kept in the side bar: a click puts it back, the pencil renames it, the cross drops it. A kept comparison remembers which of its files you had ticked as reviewed, and the ...
Read more

v1.37.0

Choose a tag to compare

@VictorQuilgars VictorQuilgars released this 18 Sep 14:14

Added

  • Make your own theme. Settings › Appearance › Create a theme opens a drawer over the app, and the app is the preview: a theme is twenty-four seeds, everything else derives from them, and changing one repaints the whole window, graph included. Start from the theme in use or from an installed one; the validator's rules are shown live beside the seed they are about; an inspect mode answers the other question — click anything in the window and see which seed colours it, with a jump to that seed. A seed answers where it makes a real part of the colour — a third or more — so hovering text boxes the text, not the frame it tints by a tenth, and a pressed button is its accent, not the text mixed into it. Saving installs the theme through the same store and validator as one from the bank, and puts it in use; the file it exports is the bank's own format, and a pasted one loads. Local to the machine; sharing to the bank is the next step. The themes above it are a shelf now: every one, on two rows that slide sideways and fade in from the edge, with the bank's card standing still at their end. (#242)
  • A minimap of the activity above the panes. A block of its own, under the toolbar and as wide as the side pane, the graph and the details together, draws the loaded history day by day — commits, or lines changed — newest on the left, with HEAD and its upstream on the top edge, ticks for local branches and stashes (remote branches and tags on request), the stretch the graph has on screen, and the days the search matched. Hover a day for its date, its count and its refs; click it and its commit is selected and scrolled to; drag across it to zoom, double-click or Exit zoom to come back; the wheel over it scrolls the graph; the gap under it is its handle, and the height it is dragged to is kept. It is built from the rows the graph holds, so Load more widens it. The Minimap switch in the toolbar shows and hides it, as do its own menu, the graph header's right-click menu and Settings › Graph; it stays as it was left.
  • The panes are cards. Sidebar, graph and panel sit as rounded cards on a darker frame, set apart by a gap rather than by a line — the way VS Code lays out its parts, and the layout the themes were drawn for. It is the default; Settings › Appearance › Layout offers Flush, the edge-to-edge rendering the app had, for anyone who prefers it, and compact density takes the frame in with everything else. The VS Code panel gets it too, its rail and compact toolbar as the frame and the rest as cards. (#240)
  • Two submodule actions that were missing: empty it, and re-read its URL. The sidebar could initialize a submodule and update it, and that was all — the last two gaps in the internal git-coverage matrix. Right-click a submodule now also offers Sync the URL, for when its remote moved and the change arrived as a commit to .gitmodules: git keeps fetching from the URL written into .git/config at clone time, so until this runs every update still goes to the old host. And Empty the working tree, which frees the checkout while leaving the submodule declared and re-initialisable. That one asks first, and no --force is ever sent — git refusing when there is work that is not pushed is the whole safety of the command, and its refusal is shown rather than swallowed. (#86)

Fixed

  • A menu closes when you do something else. It closed on a press elsewhere only when that press produced a mousedown — and a splitter cancels its press to keep the drag from selecting text, so a press on the gap under the minimap, or between the panes, left an open menu up. Presses are caught before any control can cancel or keep them now, and the window losing the focus — another app clicked — closes it too. A press on the background of the toolbar or the tab strip was the last hole: they move the window, and a drag region hands the press to the system, never to the page — while a menu is up, nothing drags the window. The minimap's options button toggles its menu: a second press puts it away.
  • A submenu near the window's right edge opens on the left. A submenu always opened to the right of its row, so one near the right edge — the minimap's Markers, the Reset modes of a commit right-clicked near the edge — was drawn past the window, unseen and out of reach. With no room on the right it opens on the left now, and is lifted when it would run past the bottom. The menu itself is clamped by its real size: it opens with a small scale-in, and a size read on that first frame left a menu opened against the right edge a few pixels over it, its border cut off.
  • The CLI speaks English. The terminal UI predates the English-only rule the app and the extension were swept for, and it still carried fifty-one sites of French: the whole help panel, every status line, the sidebar's section headers, the column titles, and thirteen error messages from the git layer — Conflit de rebase, Aucun remote configuré, Rien à rétablir. It is translated, the section headers now read as the desktop's do (LOCAL, REMOTES, TAGS), and a test reads the sources so the next one fails in CI rather than on screen. (#77)
  • In the VS Code panel, the graph follows the editor's theme instead of keeping the old colours. The graph resolves the ten branch colours to real values once — a var() cannot be added to anything, and it does arithmetic on them to fade an edge toward the canvas — and bakes one into every commit of its layout. When the editor's theme changed under the panel, everything the stylesheet owns repainted and the branches did not, until something unrelated moved the layout again. On the desktop this was hidden rather than absent: the settings page is a full-page tab, so leaving it rebuilds the graph from scratch and the colours came back right by accident. They are right on purpose now. (#160)
  • The working-tree row counted a file twice. Stage everything, then touch one of the files again: git status lists it in both columns, the staging pane rightly shows it twice — once to commit, once still to stage — and the number on the WIP row and in the pane's header added the two lists, so two files read as three. The count is over files now, on the row, in the header and in the N of M staged badge. (#232)
  • A theme's accent was the outline of every control. The one border seed was read from a VS Code theme's structural separators first — panel.border, the line above the terminal, which Dracula paints in its purple on purpose — and it lands on inputs, chips, rows and cards alike. It is read from the theme's own separators now — the section line, the panel edge — composited over the canvas when the theme writes them with an alpha; a border that is a colour of its own, or that sits on the far side of the canvas from the text where nothing can see it, is derived instead: the canvas a step toward the text, which is the light grey VS Code itself draws where a theme sets nothing. Fifteen of the thirty-two built-in themes change their line — Dracula's purple becomes a quiet grey-blue — and the validator refuses a border that is not its canvas a shade off, measured in Oklab's chroma plane: the same rule the bank is generated against, so nothing served is refused at the door.
  • A theme's accent is the colour it marks things with, not its button. The accent seed was read from the link colour, then the button — and Dracula's button is its grey current line, so the commit button, the links and every accent in the app were grey while its pink went, by accident, to the model's colour. The accent is now the colour a theme uses most where VS Code marks the user's action or attention: the button, the link, the activity-bar badge, the progress bar, the focus ring, the active tab and panel title, the remote item — greys not voting. The model's colour is the theme's second such colour when it has one of a clearly different hue, Dracula's purple beside its pink; otherwise the theme's own violet, or the lane nearest it. Twenty-two of the thirty-two built-in themes change their accent — Dark+ and Light+ get VS Code's blue back, Catppuccin its mauve — and 516 themes of the bank stop having a grey one.
  • The graph's lanes start at the accent, and no lane is a diff colour. An imported theme's ten lanes are samples around its hue wheel, and the wheel began at red: the branch you are on, first drawn, was red in Dracula — its removed lines red, to the byte, with an added-lines green three lanes over. The wheel now starts at the hue nearest the accent, as the default theme's does, so the current branch carries the theme's colour; and a lane that reads as one of the four semantic colours is left out while six colours remain, below which two neighbouring branches would share one, which is the worse reading. Fewer than ten are walked in order and wrap. Every built-in theme's lanes change. (#237)

Git Vertex VS Code Extension v1.35.0

Choose a tag to compare

@github-actions github-actions released this 18 Sep 14:16

Git Vertex VS Code Extension v1.35.0

Added

  • Make your own theme. Settings › Appearance › Create a theme opens a drawer over the app, and the app is the preview: a theme is twenty-four seeds, everything else derives from them, and changing one repaints the whole window, graph included. Start from the theme in use or from an installed one; the validator's rules are shown live beside the seed they are about; an inspect mode answers the other question — click anything in the window and see which seed colours it, with a jump to that seed. A seed answers where it makes a real part of the colour — a third or more — so hovering text boxes the text, not the frame it tints by a tenth, and a pressed button is its accent, not the text mixed into it. Saving installs the theme through the same store and validator as one from the bank, and puts it in use; the file it exports is the bank's own format, and a pasted one loads. Local to the machine; sharing to the bank is the next step. The themes above it are a shelf now: every one, on two rows that slide sideways and fade in from the edge, with the bank's card standing still at their end. (#242)
  • Git Vertex in the side bar. The view lives wherever VS Code lets a view live: the bottom panel it opens in, the primary side bar, the secondary one. Drag it to the activity bar, or run Git Vertex: Move to Side Bar and Move to Panel from the view's title menu or the command palette; an activity-bar icon carries the mark and waits, empty and invisible, until the view is put there. It is the same view with the same state wherever it goes — which is the whole point, and what the next entry is about.
  • A narrow column fits. Below 640 px the panel changes shape instead of clipping. The rail narrows to 36 px and stays; the view a rail icon opens floats over the graph as a layer, closed by Escape or a press anywhere else, rather than taking a column the graph does not have. The details — the staging pane, a commit — go under the graph, with a splitter between them whose height is remembered, or replace it with a way back when the column is short as well. The toolbar keeps the branch and the sync actions with their counts, folds the rest behind a "⋯" menu, and gives the search field a row of its own; in a short column a button reveals it. At 300 px the old single row lost Undo, Redo, Settings and the search field off its right edge — nothing is cut off now, and the panel's own geometry check runs the column at 320 × 800 and 320 × 400 on every change.
  • The terminal names commits, and they are links. A SHA, a branch, a tag or a range like main..feature printed in an integrated terminal — by git log, a test runner, a coding agent — is underlined on hover; a click shows the commit in the graph, brought forward wherever the view lives, or opens the comparison. A word is a link only when the repository has a ref of that name, and a run of digits is a number, not a commit.
  • A commit named from outside is shown in the graph. The blame hover gains Show in Graph beside File History; Git Vertex: Show Commit in Graph in the palette asks for a SHA, a branch or a tag. The commit is selected and scrolled to; when it lies beyond the page the graph holds, the page grows to reach it the way the extended search reaches a hit, up to the same limit, past which its position is said instead — and a commit on no branch the graph shows says so too.
  • The keyboard reaches the rows that matter. In the graph, h jumps to HEAD, u to its upstream, w to the working changes, Home and End to the ends of the page — plain letters, never a chord, and never while typing.
  • The view's header says what is in it. The changed-file count is a badge on the view's title (and on the panel's tab while it is collapsed, the way the Source Control view counts), and the branch is the description beside it — wherever the view is, in the one place the webview itself cannot reach.
  • A workspace with several repositories: the panel switches between them. The name in the toolbar becomes a picker when the workspace folders belong to more than one repository; choosing one puts it on screen, and the watchers, the editor tab, the status bar and the rebase detection follow it. The choice is remembered per workspace. The panel used to show the first folder's repository and nothing let it show another.
  • The graph names the stretch of time it is scrolled to. A small band at the top right of the graph reads Today, Yesterday, This week, This month or August 2026 for the first visible row, and a hairline marks where one stretch ends and the next begins — so a long scroll down a tall column still says when. It appears once the page spans more than one stretch; Date bands in the graph header's menu and in Settings › Graph turns it off. Both products.
  • A minimap of the activity above the panes. A block of its own, under the toolbar and as wide as the side pane, the graph and the details together, draws the loaded history day by day — commits, or lines changed — newest on the left, with HEAD and its upstream on the top edge, ticks for local branches and stashes (remote branches and tags on request), the stretch the graph has on screen, and the days the search matched. Hover a day for its date, its count and its refs; click it and its commit is selected and scrolled to; drag across it to zoom, double-click or Exit zoom to come back; the wheel over it scrolls the graph; the gap under it is its handle, and the height it is dragged to is kept. It is built from the rows the graph holds, so a day on it is always a day the graph can show, and Load more widens it. It hides from its own menu, the toolbar's switch, Minimap in the graph header's menu or Settings › Graph, and stays hidden; the desktop's toolbar has a Minimap switch of its own. Both products.
  • A Welcome page, once. A fresh install opens a page that says what the extension does and where, in six cards — the graph where you want it, the changes and the commit, blame in the editor, the terminal and the editor reaching the graph, the model, the look — each with a gesture that runs the thing rather than describing where to find it. An update keeps opening What's new instead; Git Vertex: Welcome reopens the page. Git Vertex: Open Panel Settings opens the panel's own settings page from anywhere.
  • The graph can follow the cursor. A switch in the toolbar (the eye), or Git Vertex: Toggle Follow Cursor: on, the commit of the line under the cursor — its blame — is selected in the graph as the cursor moves, quietly: no focus taken, nothing said when the commit is off the loaded page, nothing for a line not committed yet. Off, the graph keeps what you selected. The setting is remembered.
  • The overview is a home. The rail's first view answers "where am I, and what is next" in one place. The card of the current branch gains its issue, its pull request — or the door to one — and where it stands against the branch it will merge into (3 commits behind main · 1 ahead), and offers the one state action that is true: publish, pull or push, the rows the staging pane's empty state already computed, now where the branch is. Under it, Recent: the local branches whose tip moved within a timeframe (a day, a week, a month — remembered), newest first, each saying when, how far from its upstream, and which pull request it carries; a click shows the branch in the graph, a double-click switches to it. Then Waiting on you: how many pull requests need your review, how many of yours have changes requested, how many are approved — three searches the API already answered. Then what to start: an issue, a branch, a worktree, a stash. Every branch row now carries the date of its tip, from git's own for-each-ref, in one field more of the same process — both products.
  • A file's history can follow the editor. The File History tab gains a switch, Follow editor: pressed, the tab shows the history of whatever file the editor moves to, inside the tab's repository, and retitles itself; released, it stays on the file it is on. A history asked for a file the following tab already reached lands on that tab rather than beside it.
  • Who works here. The overview gains a Contributors section — the authors git's own shortlog counts, most commits first, merges left out, across every branch — and a row narrows the graph to that author; the same row again widens it back. The search field learned the operator behind it: author:name matches who wrote the commit and nothing else, where a bare word still matches the message and the hash too. Both products; the git call is one function in the shared core, run by both.
  • A panel with no repository says so, and offers the doors. The open folder is not a repository, or no folder is open: the centre no longer shows a graph with "no commits yet" but names the situation and offers what fits it — Initialize Repository when a folder is open, the way VS Code's own Source Control view does; Open Folder… and Clone Repository… when none is — every one of them VS Code's own, run from an allow-list. Initialising is noticed: the panel looks again and fills in.
  • Step through a file's revisions from the editor's title bar. Open Changes with Previous Revision on a working file compares it with HEAD while it is modified, and with the commit before the last one that touched it once it is clean; from a revision document it goes one commit further back, and Open Changes with Next Revision one forward, up to the working file again. A revision document also offers Show Revision Commit in Graph. The file's own history is the chain, so a file touched once a year steps once a year.
  • The status bar opens the panel. The branch in the status bar is the most visible door to the extension, and it launched the desktop app — which is not always installe...
Read more

v1.36.0

Choose a tag to compare

@VictorQuilgars VictorQuilgars released this 12 Sep 23:14

Added

  • A reading density, compact or comfortable. Body text was 12–13px and metadata went down to 9 and 10px, and the only answer was the zoom — which scales every pane together and makes a short window cramped sooner rather than later; the audit measured 900 × 600 as unusable before any zoom was applied. Settings › Appearance › Density now offers two, each previewing itself. Comfortable is what the app has always drawn, so nothing moves unless you ask it to. Compact takes away air, not letters: row heights come down (the graph from 28 to 24px, the whole left column from 26 to 22), the padding steps tighten, and the two body text sizes drop one step — while the smallest text does not move at all, because it was the thing that was too small in the first place. That one is fixed for everyone, at both densities: metadata that was 9 and 10px is 10 and 11px now. The graph follows properly rather than approximately — it reads the row heights back out of the stylesheet and re-lays its nodes and edges, so the commits stay aligned with the text they describe. (#195)
  • A journal of what happened to each repository, behind the bell. A toast was the only record of an operation: four fit on screen, the fifth pushed the first off for good, and a failed push read past four fetches later was simply gone. Every operation the app reports on — push, pull, fetch, merge, rebase, stash, commit, and everything else that raises a chip — is now also written down under the repository it ran on, and the bell is where you go back to it. Errors first, each line naming its repository and how long ago it was, the same words the chip used. An error chip carries a quiet Journal link to its own entry, so the chip is no longer the only copy; the bell's badge counts the failures of the repository on screen that have not been read, and opening it is reading them. With sessions, an operation that started on one repository and reports after you have switched away goes to its journal, not to whichever tab is in front — so it is waiting there when that tab comes back. Kept in memory for the session and bounded per repository: an error text is about a working tree as it was, and it can carry a path or a remote URL. (#193)

Changed

  • Opening a repository got faster, and opening one you have opened before is instant. A refresh was fourteen git processes in six waves, each waiting on the last — which on Windows, where starting git.exe costs an order of magnitude more than running it, is where the time went. It is five processes in two waves for a clean working tree, seven for a dirty one, and a test holds those numbers down. What went: the signature verification — %G? is not a field but a verification, one gpg process per signed commit, and nothing has drawn the result since the badge was removed on 28/08/2026; on this repository's own history a 200-commit page was 580 ms with it and 150 ms without, and a repository whose merges all come from the GitHub button is signed on every row. The second git status — the conflict list and the working changes each asked for their own, and on NTFS behind a virus scanner that is the slowest read the app makes, done twice. Two diffs of nothing — the staged and unstaged line counts were read beside the status rather than after it, so a clean tree paid for both. Three processes recomputing ahead/behind that the branch list already had. Two questions that cannot change while a repository is open — where its .git is, and whether it has a HEAD — now asked once instead of on every refresh. And the branch list is one for-each-ref instead of git branch -a --verbose plus a second call: out of plumbing rather than out of a sentence written for humans, which also retires the repair that turned * (HEAD detached at 1a2b3c4) into a branch called (HEAD. The six waves are two, with the graph alone in the first — firing all six together was tried and measured and cost 85 ms, because five more git processes take CPU and disk from the one query you are waiting for. Measured end to end on a 20,000-commit repository: 178 ms to 168 ms here, where none of the commits are signed and the working tree is one file — the changes that do the most are the ones this machine cannot show.
  • The graph a repository had last time is on screen before git says a word. The same 20,000 commits open in 42 ms on a later visit instead of 168, because the previous graph is drawn in the first frame while the real one is being read. Nothing is skipped and no answer is taken from the cache: the refresh runs exactly as it would have, silently, and replaces what is drawn when it lands. What is not kept is the working tree — conflicts, the conflict mode, the count of uncommitted files — because those change while the app is closed, and a stale conflict banner is a wrong statement rather than a slightly old graph. Six repositories, a page of commits each, thirty days; closing a repository forgets it.
  • Git's own caches, for repositories that need them — Settings › Behaviour › Speed up large repositories. Past a certain size the app's own cost stops being the story: git status walks the working tree, and on NTFS behind a virus scanner walking a large one is seconds however few times it is asked. Git has an answer, core.fsmonitor — a daemon that watches the tree so status stops walking it — and it is off by default in every repository. Switching this on writes it, plus fetch.writeCommitGraph, into each repository the first time it is opened, and writes that repository a commit-graph so history can be walked by generation number instead of by opening every commit object. Off unless asked for, because this goes into the repository's own config and every git client on the machine reads it afterwards; the row names the keys, the way the identity fields do, and git config --unset undoes it. A value you set yourself is never replaced — it is very possibly a path to your own hook. Nothing is written where git cannot support it: the daemon is git 2.37 and later, on Windows and macOS. core.untrackedCache is deliberately not in the list, although it belongs there on merit: git's own test for whether a filesystem can carry it writes a file into the working tree and sleeps on it for six seconds, and a feature meant to be invisible does not do that behind your back. And beside it, on Windows only, the thing this application cannot fix. Defender's real-time protection inspects every file as it is opened, and git status on a large repository opens all of them — which is why the same repository with the same git is quick on one machine and slow on another. Excluding the folder your repositories live in routinely beats everything above put together. The note says so, gives the one-line PowerShell for it, says what it does and does not cover and how to undo it — and copies rather than runs it: it changes the machine's security settings, which belongs to whoever owns the machine.
  • A build running in an open window no longer buys a refresh every 1.5 seconds. The working-tree watcher is recursive, so it saw node_modules, dist, coverage output and every other thing the repository ignores — and each of those was answered with a full refresh. What the watcher collects is now put to git check-ignore first, one process for the whole batch, with the answer per path remembered so an ordinary edit pays once and a build pays once for its files. The authority is git rather than a list of directory names, because dist is ignored in one repository and committed in the next. Everything uncertain still refreshes: git failing to answer, a batch too large to be an edit, or a .gitignore in it. The watcher inside .git got the same treatment for what cannot be news on its own: object writes and lock files. A fetch writes thousands of loose objects, and because the debounce is trailing they did not merely cost events — they held the refresh back until the fetch finished. That last one is also a fix — the watcher's test for the .git directory matched by prefix, so an edit to .gitignore or .gitattributes never refreshed anything, and those are the two files in the tree that change what the staging area shows.
  • The two products now run one implementation of a diff. Reading a commit, comparing two refs, listing what a comparison touched, a working-tree diff, a stash's patch, a blame, a search through diffs: the desktop app and the VS Code panel each had their own copy of all of it, and the copies drifted — the blame dates above are what that looks like from the outside. There is one now, shared, with each product keeping only its own way of reaching git. Nothing about what these produce was meant to change beyond the fix above. (#191)

Fixed

  • Blame dates are written in English again. Blame in the commit panel dated every line with the French calendar — 11/09/2026, read as the 11th of September by a UI that is English-only everywhere else, and as the 9th of November by anyone who took it at face value. The VS Code panel, running the same view, had always written 9/11/2026. The date is no longer taken from the machine the app happens to run on. (#191)

Git Vertex VS Code Extension v1.34.0

Choose a tag to compare

@github-actions github-actions released this 12 Sep 23:16

Git Vertex VS Code Extension v1.34.0

Added

  • A reading density, compact or comfortable. Body text was 12–13px and metadata went down to 9 and 10px, and in a panel docked to the side of an editor that is where the room runs out first. Settings › Appearance › Density now offers two, each previewing itself. Comfortable is what the panel has always drawn, so nothing moves unless you ask. Compact takes away air, not letters: row heights come down (the graph from 28 to 24px, the whole list column from 26 to 22), the padding steps tighten, and the two body text sizes drop one step — while the smallest text does not move at all, because it was the thing that was too small in the first place. That one is fixed for everyone, at both densities: metadata that was 9 and 10px is 10 and 11px now. The graph re-reads the row heights out of the stylesheet and re-lays its nodes and edges, so the commits stay aligned with the text beside them.
  • Git's own caches, for repositories that need them — Settings › Behaviour › Speed up large repositories. Past a certain size the panel's own cost stops being the story: git status walks the working tree, and on NTFS behind a virus scanner walking a large one is seconds however few times it is asked. Git has an answer — core.fsmonitor, a daemon that watches the tree so status stops walking it — and it is off by default in every repository. Switching this on writes it, plus fetch.writeCommitGraph, into each repository the panel opens, and writes that repository a commit-graph. Off unless asked for, because it goes into the repository's own config and every git client on the machine reads it afterwards; the row names the keys, and git config --unset undoes it. A value you set yourself is never replaced, and nothing is written where git cannot support it.
  • On Windows, the settings say what the extension cannot fix. Defender's real-time protection inspects every file as it is opened, and git status on a large repository opens all of them — which is why the same repository with the same git is quick on one machine and slow on another. Excluding the folder your repositories live in routinely beats everything above put together. The note gives the one-line command, says what it does and does not cover and how to undo it, and copies rather than runs it: it changes the machine's security settings.

Changed

  • The panel stopped verifying a signature it never draws. %G? in the log query is not a field but a verification: git runs gpg once per signed commit on the page, and the graph has drawn no signature at all since 28/08/2026. Measured on the desktop's own repository, a 200-commit page was 580 ms with it and 150 ms without — and a repository whose merges all come from the GitHub button is signed on every row, so the whole page was paid for.
  • One git status per refresh instead of two. The conflict list and the working changes each asked for their own, which on a large working tree — and especially on NTFS behind a virus scanner — is the slowest read the panel makes, done twice. Readers that overlap in time now share the one in flight, which also stops two git processes rewriting .git/index at the same moment.
  • The branch list is one git process, and comes out of plumbing. It was git branch -a --verbose — text git writes for people, parsed with a regex — followed by a second call for ahead/behind. One for-each-ref answers both in fields, which also retires the repair that turned * (HEAD detached at 1a2b3c4) into a branch called (HEAD, and gives origin/HEAD a real hash where it used to show ->.
  • One implementation of a diff, shared with the desktop app. Reading a commit, comparing two refs, listing what a comparison touched, a working-tree diff, a stash's patch, a blame, a search through diffs: this extension and the desktop app each carried their own copy of all of it, and the copies had drifted — the desktop dated blame lines with the French calendar while this panel used 9/11/2026, same view, same method, two different dates. There is one implementation now, with each product keeping only its own way of reaching git. Nothing the panel produces was meant to change.
  • The graph a repository had last time is on screen before git answers. The panel draws the previous visit's graph in the first frame and replaces it when the real one lands; nothing is skipped and no answer comes from the cache. The working tree is deliberately not kept — a stale conflict banner is a wrong statement rather than a slightly old graph.

Installe le VSIX directement :

code --install-extension git-vertex-1.34.0.vsix

Ou cherche Git Vertex dans le Marketplace VS Code.

🔗 VS Code Marketplace
🔗 Open VSX

v1.35.0

Choose a tag to compare

@VictorQuilgars VictorQuilgars released this 08 Sep 18:02
5168574

Added

  • A clean working tree says what comes next, on the desktop too. The staging pane has offered next steps since v1.22.0 — publish this branch, push the commits waiting, pull what arrived, review what the branch would bring, and a list of things to start — but only inside the VS Code panel. On the desktop the same clean tree was an empty Unstaged list, an empty Staged list and a commit button that could not be pressed. It is the same card now, computed the same way and following the same rule: a row is drawn only when it is true of this repository — no Publish on a published branch, no Push 3 on a branch level with its upstream, and nothing to publish at all in a repository with no remote. Where a row leads to a list rather than to an action — apply a stash, switch branch, start from an issue — the desktop opens that section of the sidebar and scrolls to it, since the desktop stacks its sections instead of choosing one on a rail. Two things it never replaces: an amend being written, and a message already typed — a draft outlives the changes it was written for, and a card of suggestions over the top of it would take your own words off the screen without deleting them. And it waits until the working tree has actually been read before saying there is nothing in it. (#189)

Changed

  • Electron 32 → 44: the browser this app ships is supported again. An Electron app carries its own Chromium and its own Node, and Electron only patches the latest three majors. This one was twelve behind — the Chromium inside it was from August 2024 and had received no security fix since. It now runs the current stable, which is the whole point of the change; nothing about the app's own behaviour was meant to move with it. Two things do move, and neither is optional:
    • macOS 13 (Ventura) is now the minimum. Electron dropped macOS 11 in v38 and macOS 12 in v44. In practice this is a hardware line as much as a version one — every Mac that cannot run Ventura is an Intel one (broadly a 2017 model or older; 2018 for the Air and the mini, 2019 for the Mac Pro). Intel Macs that can run Ventura lose nothing: each release still carries its own x64 build beside the arm64 one, and the update feed serves both. For the rest, the build declares its floor (LSMinimumSystemVersion) so macOS refuses to open a version it cannot run — and the update feed now declares it too, so the updater no longer offers that version at all: v1.34.0 is where those Macs stop, working, rather than being replaced by something that will not start. Windows 10+ and the Linux builds are unaffected.
    • Notifications on macOS need a signed app. Electron 42 moved macOS notifications to the system's UNNotification API, which refuses to deliver for an application that is not code-signed — and this app is not signed today. On macOS the three Notify settings therefore do nothing until it is; nothing else in the app depends on them, and Windows and Linux notifications are unaffected.
      Also from the upgrade, and smaller: a dialog opened with no starting folder now opens on Downloads rather than on the last folder used, so Open a repository is told to start beside the repository you opened last. On Linux, Electron 38 made Wayland the default where the session offers it, and Electron 43 gives frameless windows rounded corners — the splash is one, so it looks slightly different there.
  • Every argument is looked at before it reaches git. The window runs sandboxed, the secrets never reach it and every request names the repository it is about — and then each handler took the arguments as they came. A ref, a file path inside the repository, a remote name, a clone URL: what checking existed was inside individual methods and by memory, not at the door. There is a door now. One table says what each git:* handler's arguments may be, and a call that breaks it is answered with a sentence saying which argument and why — never a rejected promise the window has to guess at. What it refuses: anything git would read as an option (--upload-pack=… as a branch name), control characters and newlines, a name for a new branch or tag that git check-ref-format would reject, a remote name with a slash in it, a clone URL whose scheme is neither http(s), ssh, git nor file — and a file path that leaves the repository, so a request for ../../.ssh/id_rsa is not a file of this repository whichever pane asked for it. What it does not do is invent opinions about missing values: an argument nobody sent, or sent empty, reaches the handler exactly as before. A test reads the handlers as they are written and fails when one grows an argument that looks like a path or a ref and the table says nothing about it — it found five the first time it ran. (#190)
  • The settings say what they change, and when they are kept. The page held two kinds of setting and presented them identically: what belongs to this app — a theme, an auto-fetch interval, an API key — and what writes Git's own global configuration, which every git client on the machine reads afterwards. The second kind now says so in the field itself, with the key it writes: Git global · user.name on the identity, Git global · core.sshCommand on the SSH key and the agent switch — the two places where a choice made here leaves this app. The fields that only look git-shaped carry nothing: GPG signing adds -S to the commits this app makes and writes nothing to ~/.gitconfig, and a chip there would be the same confusion in a smaller font. The save modes are said rather than discovered: each block reads either Saved as you change it. or Nothing here is saved until you press Save. — one mode per block, in words, instead of a page where some fields kept themselves and others waited for a button with nothing to tell them apart. The identity's description said these values "sign your commits", directly above the block that actually signs them; it now says what they are, the name and email your commits are authored with. And the explanation of why the app has to go looking for git — the truncated PATH of an app launched from the Finder — folds away behind Why this app has to look for git: a diagnosis worth reading once and in the way every other time. The setting itself stays where it was. (#197)

Git Vertex VS Code Extension v1.33.0

Choose a tag to compare

@github-actions github-actions released this 08 Sep 18:05
5168574

Git Vertex VS Code Extension v1.33.0

Changed

  • The commit pane stops guessing, twice. The next-steps card it shows on a clean working tree was drawn from the state the pane starts with — empty — so it appeared for a frame on every repository as you opened it, however many files were waiting to be staged. It now waits until the working tree has actually been read: on a repository with changes, the file list is the first thing you see. And a commit message you have already typed keeps its form: a draft outlives the changes it was written for — discard them, or stash them, and the words are still yours — where before the card replaced it and took your own text off the screen without deleting it. An amend being written was already excluded; this is the same rule, applied to the other way a commit is in progress.
  • The settings say what they change, and when they are kept. The page held two kinds of setting and presented them identically: what belongs to this extension, and what writes Git's own global configuration — which every git client on the machine reads afterwards. The identity fields now carry a chip naming the file and the key they write, Git global · user.name, because saving them runs git config --global and that is not a fact you should have to know. The fields that only look git-shaped carry nothing. And each block says once how it is saved — Saved as you change it. or Nothing here is saved until you press Save. — instead of leaving you to find out by watching. The identity's description said these values "sign your commits", directly above nothing of the sort; it now says what they are, the name and email your commits are authored with.

Installe le VSIX directement :

code --install-extension git-vertex-1.33.0.vsix

Ou cherche Git Vertex dans le Marketplace VS Code.

🔗 VS Code Marketplace
🔗 Open VSX