Git Pros — VS Code Extension
Run your Git command profiles from a sidebar, stage/commit/push file changes, resolve
conflicts, switch branches (with auto-pull), merge or cherry-pick after a commit, and
browse commit history — all inside one activity bar container, split into three sections.
Table of Contents
Look for a Git Pros icon in the left activity bar. Clicking it opens three collapsible
sections:
GIT PROS (activity bar container)
├─ ▾ Git Pros -> your saved command "profiles" (Normal, Migration, etc.)
├─ ▾ Changes -> stage / unstage / discard / resolve conflicts / commit
└─ ▾ Git Actions -> switch branch, commit history, command log
Each section has its own title-bar toolbar (icons in the top-right corner), detailed below.
1. "Git Pros" section — Command Profiles
Save your repeated Git command sequences under a name, and run them with one click/checkbox.
GIT PROS [+] [🔑] [⟳]
├─ ▸ Normal [▶] [+] [✎] [🗑]
│ ☑ git add .
│ ☑ git commit -m "update"
│ ☑ git push
├─ ▸ Migration [▶] [+] [✎] [🗑]
│ ☑ git add .
│ ☐ git commit -m "migration"
│ ☑ git push origin migration
| Icon |
Command |
What it does |
+ |
gitProfiles.createProfile |
Opens the full form panel to create a new profile |
| 🔑 |
gitProfiles.setAuthentication |
Set up Authentication (name, email, host, token) |
| ⟳ |
gitProfiles.refreshView |
Manually refresh the tree |
How to use it
- Click
+ → fill in a profile name and its commands → Save Profile.
- In the sidebar, click ▶ (Run Checked) next to a profile → only the checked (☑)
commands run, in order, in the terminal.
- To skip a command temporarily, just uncheck its box — this only affects this run, it doesn't
change the saved list in settings.json.
Each profile row
- Clicking the profile name only expands/collapses the row — it never runs a command (this is
intentional, for safety).
- + (Add Command) opens the same full form panel, pre-filled with the profile's name and all
its commands.
- ✎ (Rename) changes just the profile's name (a quick inline input).
- 🗑 (Delete) removes the profile (asks for confirmation first).
- Hover over any command line to see its own ✎ Edit / 🗑 Delete icons.
- Right-click a profile → Select All Commands / Deselect All Commands.
Full form panel (Name + Commands in one page)
┌─────────────────────────────────────┐
│ Profile Name │
│ [ Frontend ] │
│ │
│ Commands │
│ [ git add src/ ] [✕] │
│ [ git commit -m "frontend" ] [✕] │
│ [ git push origin frontend ] [✕] │
│ [+ Add Command] │
│ │
│ [ Save Profile ] [ Cancel ] │
└─────────────────────────────────────┘
Clicking or typing into any command box opens an autocomplete dropdown with common Git
commands and a short description — it's just a helper, you can also type your own custom command
directly.
Editing settings.json directly (the fastest way)
"gitProfiles.profiles": {
"Normal": ["git add .", "git commit -m \"update\"", "git push"],
"Migration": ["git add .", "git commit -m \"migration\"", "git push origin migration"]
}
The {branch} placeholder
Type {branch} anywhere inside a command, and right before the profile runs it's replaced with
whatever branch is currently checked out — so the same profile works no matter which branch
you're on, instead of needing a separate, hardcoded-branch-name profile for each one.
git reset --hard origin/{branch}
On branch dev this actually runs git reset --hard origin/dev; switch to test first and the
same saved command runs git reset --hard origin/test instead.
If no folder is open, or it isn't a Git repository, the profile shows a warning and doesn't run —
so it never sends a command with the literal, unresolved text {branch} still in it.
2. "Changes" section
Like VS Code's built-in Source Control, but a custom-built version — file-level stage/unstage, an
inline diff viewer, discard, conflict resolution, and commit, all with a checkbox-based UI.
CHANGES [✔] [🗑] [❌] [↩] [✓] (⬇ ⬆ only show up when there's a conflict)
├─ ▾ Merge Conflicts (1) <- only shown when a file is conflicted
│ ⚠ src/App.jsx [⬇][⬆]
├─ ▾ Staged Changes (2)
│ ☑ src/App.jsx M
│ ☑ src/utils/helpers.js A
└─ ▾ Changes (1)
☐ src/index.js M
| Icon |
Command |
What it does |
| ✔ |
gitProfiles.stageAllChanges |
Stages every changed file at once |
| 🗑 |
gitProfiles.discardAllChanges |
Discards every changed file at once — staged or unstaged, checked or not (asks for confirmation) |
| ❌ |
gitProfiles.unstageAllChanges |
Unstages every staged file at once |
| ↩ |
gitProfiles.revertCheckedFiles |
Reverts every checked (staged) file back to the last commit (asks for confirmation) |
| ✓ |
gitProfiles.commitChanges |
Opens the Commit panel |
| ⬇ |
gitProfiles.acceptAllIncoming |
(only shown when there's a conflict) Keeps the "Incoming" side for every conflicted file at once |
| ⬆ |
gitProfiles.acceptAllCurrent |
(only shown when there's a conflict) Keeps the "Current" side for every conflicted file at once |
Each normal file row
- Checkbox — checking it stages the file, unchecking unstages it. The UI updates
instantly.
- Clicking the file name opens its diff.
- Hovering shows: ↩ Discard Changes (just this file), 🕐 Revert to Specific Commit... (pick
any earlier version of this file from its history and revert to it).
Merge Conflicts group
This group appears automatically whenever a file is conflicted — whether from a normal
git merge/cherry-pick conflict, or a conflict caused by carrying uncommitted changes across
a branch switch. Both kinds are detected.
- Clicking the file opens the Resolve Conflict panel.
- The row's inline ⬇/⬆ buttons resolve just that one file, taking the whole "Incoming"/"Current"
side.
Conflict resolve panel
Clicking a conflicted file opens a dedicated screen:
RESOLVE CONFLICT
src/App.jsx
[Keep Current for all (2)] [Keep Incoming for all (2)]
┌─ Conflict 1 — Unresolved ──────────────────┐
│ Current: Updated upstream [Keep This] │
│ return 1; │
│ Incoming: Stashed changes [Keep This] │
│ return 2; │
└─────────────────────────────────────────────┘
┌─ Conflict 2 — Unresolved ──────────────────┐
│ ... │
└─────────────────────────────────────────────┘
[ Apply Resolution ] [ Cancel ]
How to use it:
- Each conflict block shows the actual code from both sides — "Current" (your branch) and
"Incoming" (the other side).
- Click "Keep This" on whichever side you want, per block — different blocks in the same file
can keep different sides.
- To go faster, use "Keep Current for all" / "Keep Incoming for all" at the top (you can
still change individual blocks afterward).
- Once every block is resolved (a progress line at the top tracks this), Apply Resolution
becomes enabled — clicking it saves and stages the file. Commit it from the Commit panel
afterward.
Commit panel (webview)
Clicking the ✓ button, or a file, opens a full panel for committing:
┌───────────────────────────────────────────┐
│ BRANCH │
│ 🌿 feature/login (read-only) │
│ │
│ FILES │
│ [x] Select All │
│ [x] M src/App.jsx │
│ [ Apply Stage ] │
│ │
│ COMMIT MESSAGE │
│ [ ... ] │
│ │
│ [x] Push after commit │
│ │
│ [ Commit & Push ] [ Cancel ] │
│ │
│ RESULT │
│ ✅ Commit 1 file(s) [a1b2c3d] <- click to │
│ copy full hash │
│ ✅ Push to remote │
│ │
│ MERGE INTO <- unlocks only │
│ [ ] master after a push │
│ [Check other people's commits] [Merge Now] │
│ │
│ CHERRY-PICK TO │
│ [ ] master │
│ [Cherry-pick Now] │
└───────────────────────────────────────────┘
How to use it:
- Branch — only shows the current branch (read-only), no switching — so you can never
accidentally commit/push to the wrong branch.
- Files — pick which ones to stage/unstage with the checkboxes, then Apply Stage (or just
click Commit — it applies staging for you too). Clicking a file opens its diff.
- Ticking Push after commit changes the button's label to "Commit & Push" (uncheck it and
it just says "Commit").
- After clicking Commit, the Result area shows a live status for each step (Commit, Push).
Once committed, a small hash chip appears — click it to copy the full commit hash to
your clipboard (handy for cherry-picking it manually anywhere).
- "Merge Into" and "Cherry-pick To" only unlock once this panel's own commit has been
pushed — before that, they're greyed out.
- Merge Into: tick target branch(es) → optionally "Check other people's commits (no
commit / push)" first to preview whose commits would travel → click "Merge Now". If the
target branch is behind, it's pulled first; if that hits a conflict, it stops there for you
to resolve manually.
- Cherry-pick To: its own separate branch checklist — "Cherry-pick Now" sends just the
one commit made in this panel to the ticked branch(es).
- For both, protected branches (from the settings list) never get a direct push — instead a
throwaway branch is created and a Pull/Merge Request opens in your browser.
- Non-protected targets are not pushed automatically — you push them yourself.
3. "Git Actions" section
Branch-level actions — switching branches and commit history. Command Log on/off also lives here.
GIT ACTIONS [⇄] [🔗] [✅] [📄]
| Icon |
Command |
What it does |
| ⇄ |
gitProfiles.switchBranch |
Switch branch |
| 🔗 |
gitProfiles.showCommitHistory |
Opens the Commit History panel |
| ✅ |
gitProfiles.toggleCommandLog |
Turns the Command Log on/off |
| 📄 |
gitProfiles.openCommandLog |
Opens the command log file |
The status bar (bottom-left of the VS Code window) also shows the current branch name
($(git-branch) <branch>) — clicking it opens Switch Branch too.
Switch Branch (auto-carry + auto-pull)
Clicking ⇄ or the status-bar branch name opens a QuickPick list (all local branches, protected
ones marked 🔒). Once you pick a branch:
- If you have uncommitted changes, they're carried over to the new branch automatically,
with no popup (stash push → checkout → stash pop, all silently).
- After switching, the branch is immediately pulled from its remote (
git fetch +
git merge origin/<branch>), so you're never left working on a stale branch.
- If the pull hits a conflict, you stay on that branch — nothing gets auto-aborted. The file
shows up under "Merge Conflicts" in the Changes view; resolve it in the
resolve panel, then
git add + commit yourself to finish the pull.
- If the branch already had an unresolved merge/cherry-pick before you tried to switch, the
switch itself is blocked with a clear message telling you to resolve or abort that first.
- If carrying your uncommitted changes over (step 1) hits a conflict with the new branch's own
version of a file, that conflict shows up the same way — under "Merge Conflicts" — and the
temporary stash used to carry it over is cleaned up automatically once git confirms the
change was actually applied, so these don't pile up in
git stash list over repeated switches.
Any stash you make yourself (or the separate "Stash Them" option) is never touched by this.
Commit History panel
Clicking 🔗 opens a webview panel:
BRANCH
[ feature/login ▼ ]
[x] Only show my commits
[ Search by commit message or author... ]
COMMITS
▸ Fix date picker validation bug abc1234 · 2026-09-05 14:22 · Aniket [🍒][↺]
M src/components/DatePicker.jsx [↺]
M src/utils/validate.js [↺]
[ Load 100 More ]
How to use it:
- Branch dropdown — pick any branch to load its commit history. "Only show my commits" is
on by default — it matches your git identity (email/name).
- Expand a commit → see exactly which files it changed (M/A/D), loaded lazily. Click a file
to see that commit's diff (before vs. after).
- ↺ next to a file (after expanding) reverts that file to how it was BEFORE this commit
(if the commit added the file, it's deleted instead). This only touches your working tree — no
commit, no push, no confirmation popup.
- ↺ next to the commit title undoes whatever that whole commit changed
(
git revert --no-commit) — working tree only, no automatic commit or push. Review it, then
commit yourself.
- 🍒 (Cherry-pick to branch) — send any commit (pushed or not) to other branch(es): a
branch-picker opens (multi-select), confirm, and it's cherry-picked onto them (a protected
branch opens a PR instead; a normal branch is pulled first, then cherry-picked onto — you push
it yourself).
- Load 100 More — load older commits with pagination.
Cross-cutting features
Command Log
Default: OFF — no log file is created unless you explicitly turn it on.
- Toggle (
gitProfiles.toggleCommandLog, ✅ icon in Git Actions) — turning it ON asks for
confirmation, turning it OFF doesn't.
- Once ON, every meaningful command is logged in two places:
- A dedicated read-only terminal ("Git Pros Log"), echoed in real time with a short
explanation.
- A log file (timestamp + command + explanation).
- File location: the
gitProfiles.logFilePath setting, or use Git Pros: Set Command Log Location to pick one with a file picker.
Git Pros: Open Command Log File (📄 icon) opens the log file in the editor.
Git Pros: Show Command Log Terminal reveals that terminal manually.
Authentication
gitProfiles.setAuthentication (🔑 icon, Git Pros toolbar) asks for your name, email, git host
(default github.com), and a password/token (masked input). On save:
git config user.name / user.email are set.
- If no credential helper is already configured, Git's own
credential.helper store is enabled.
- Your email + token are cached for that host — future push/pull won't keep asking.
Use gitProfiles.clearAuthentication to remove the cached login.
Security note: If Git Credential Manager isn't installed on your system, Git itself saves
credentials to ~/.git-credentials in plaintext (this is Git's own standard behavior) —
installing GCM is more secure.
Training Wheels (setting only)
There's a setting (gitProfiles.trainingWheels) that, when on, shows a Yes/No confirm popup
before every meaningful git command — but there's no on/off button for it in the UI anymore.
If you want it, just set "gitProfiles.trainingWheels": true directly in settings.json.
Settings reference
| Setting |
Type |
Default |
What it does |
gitProfiles.profiles |
object |
{Normal: [...], Migration: [...]} |
Named command profiles |
gitProfiles.runInSameTerminal |
boolean |
true |
Reuse one terminal for every profile run |
gitProfiles.enableCommandLog |
boolean |
false |
Command log (file + terminal) on/off |
gitProfiles.logFilePath |
string |
"" (empty = default location) |
Where to write the log file |
gitProfiles.protectedBranches |
string[] |
[] |
Branches that never get a direct merge/cherry-pick — a PR opens instead (a trailing release/*-style prefix works too) |
gitProfiles.trainingWheels |
boolean |
false |
Confirm popup before every UI-triggered command (no toggle button — change this setting directly) |
Command Palette reference
These commands are all available via Ctrl+Shift+P:
| Command |
What it does |
Git Pros: Run Profile |
Pick a profile from a list → its checked commands run |
Git Pros: Create New Profile |
Create a new profile (full form) |
Git Pros: Edit Profile |
Pick a profile from a list and edit it |
Git Pros: Delete Profile |
Pick a profile from a list and delete it |
Git Pros: Open Profiles in settings.json |
Jump straight to gitProfiles.profiles |
Git Pros: Set Authentication |
Set up Authentication |
Git Pros: Clear Authentication |
Remove the cached login |
Git Pros: Switch Branch |
Switch branch (auto-carry + auto-pull) |
Git Pros: Show Commit History |
Open the Commit History panel |
Git Pros: Resolve Conflict (side by side) |
Open the resolve panel for a conflicted file |
Git Pros: Toggle Command Log |
Turn the Command Log on/off |
Git Pros: Set Command Log Location |
Pick the log file's path with a file picker |
Git Pros: Open Command Log File |
Open the log file in the editor |
Git Pros: Show Command Log Terminal |
Reveal the log terminal |
Project structure
extension.js # Entry point: activate()/deactivate(), registers every command
src/
config.js # Settings read/write (gitProfiles.profiles), shared display name
terminal.js # Shared terminal for running profiles
commandLog.js # Command Log (file + terminal) + Training Wheels confirm helper
gitExec.js # execGit() — every git command runs through this
auth.js # Set/Clear Authentication
changes.js # stage/unstage/status + conflict detect/parse/resolve (core logic)
branches.js # branches, switch, merge, cherry-pick, protected-branch logic
changesTree.js # "Changes" sidebar tree provider (staged/unstaged/conflicted)
actionsTree.js # "Git Actions" sidebar (toolbar-only view)
profilesTree.js # "Git Pros" sidebar tree provider
profileForm.js # Profile create/edit webview form
profileCommands.js # Profile CRUD commands
diffRevert.js # Diff viewer, discard, revert, accept-conflict-side actions
conflictPanel.js # Block-by-block conflict resolve webview panel
commitPanel.js # Commit webview panel (push, merge, cherry-pick included)
commitHistoryPanel.js # Commit History webview panel (revert + cherry-pick-to-branch)
htmlUtils.js # Shared escapeHtml()
Install / try it locally
Option A — Debug mode (no packaging needed)
- Open the folder in VS Code.
- Press
F5 → an "Extension Development Host" window opens with the extension active.
- In that new window, click the Git Pros icon in the activity bar.
- If you change the source code, press
Ctrl+R (Developer: Reload Window) in that window — it
won't pick up changes otherwise.
Option B — Build a .vsix and install it (for yourself, or to share manually)
npm install -g @vscode/vsce
vsce package
code --install-extension git-pros-profiles-2.1.0.vsix
You can send this .vsix file to anyone — they can install it with code --install-extension or
the Extensions panel's "Install from VSIX...". It won't get automatic updates, though, and
nobody can discover it by searching.
Publishing to the Marketplace
This makes "install from VSIX" unnecessary — people can search for Git Pros Profiles in the VS
Code Extensions panel and install it in one click, and get future updates automatically.
Step 1 — Create a publisher account
- Go to https://dev.azure.com and create a free Azure DevOps organization (sign in with a
Microsoft/GitHub account).
- Go to https://marketplace.visualstudio.com/manage and click "Create Publisher". Choose a
unique Publisher ID (e.g.
yourname-dev) — this goes in package.json's publisher
field.
Step 2 — Create a Personal Access Token (PAT)
- Azure DevOps → top-right profile icon → Personal Access Tokens.
- New Token → Organization: All accessible organizations → Scopes: Custom defined →
select Marketplace → Manage.
- The token is shown once — copy it and save it somewhere safe (it won't be shown again).
npm install -g @vscode/vsce
Step 4 — Finalize package.json
Make sure these fields in this repo's package.json are updated:
"publisher" → your Publisher ID from Step 1 (already set to "aniketwakalkar" — just make
sure that Publisher ID actually exists on the Marketplace before publishing).
"name" → must be globally unique on the Marketplace (the publisher.name combo has to be
unique — search the Marketplace first to confirm the name isn't taken).
"repository" → your actual GitHub repo URL (recommended, not required).
"version" → a semantic version (already 2.1.0).
icon (already set to media/icon.png, a 128x128 PNG) — replace it with your own if you want.
Step 5 — Log in and publish
# Run this from inside the extension's folder
vsce login <your-publisher-id>
# It'll ask for the PAT
vsce publish
vsce publish packages and uploads it to the Marketplace for you. Within a few minutes it'll be
live at https://marketplace.visualstudio.com and searchable from within VS Code.
For future updates:
vsce publish patch # 2.1.0 -> 2.1.1
vsce publish minor # 2.1.0 -> 2.2.0
vsce publish major # 2.1.0 -> 3.0.0
This bumps the version and publishes the new one for you.
Bonus — Open VSX (for VSCodium / Cursor / other VS Code forks)
If you also want it available on open-source forks like VSCodium, not just the official Microsoft
Marketplace:
npm install -g ovsx
ovsx create-namespace <your-publisher-id>
ovsx publish -p <open-vsx-access-token>
(Get an Open VSX token by signing in with your GitHub account at https://open-vsx.org — it's
separate from the Azure PAT.)
Notes
- Profiles are saved in global settings when no workspace/folder is open, otherwise in the
current workspace settings (
.vscode/settings.json) — so different projects can have
different profiles.
- Profile commands are sent to the terminal one line at a time (Windows PowerShell doesn't support
&&, so commands aren't joined with it).
- The "Changes" section's checkboxes perform actual git stage/unstage (instantly in the
background; the UI updates optimistically).
- Auto-stash entries (made while switching branches) are tagged with a
git-profiles-carry-across-switch: prefix. If reapplying one hits a conflict, it's cleaned up
automatically once the change is confirmed applied — see
Switch Branch.
- Conflict detection catches two kinds of conflicts: (1) a real
git merge/cherry-pick
conflict (registered as "unmerged" in git's index), and (2) a git stash pop conflict, which
only leaves <<<<<<</=======/>>>>>>> markers in the file's content without registering as
"unmerged" in git's index — both are resolved the same way, in one place.
- If a merge/cherry-pick/switch hits a conflict anywhere, the extension never aborts it
automatically — it leaves the repo as-is so you can look at it and resolve it manually in the
Changes view / resolve panel.