Git for Salesforce SEs
Branches, commits, pushes, and pull requests for SEs who have never used Git in anger
A lot of SEs first encounter Git when a customer POC needs to be handed to an implementation partner, and suddenly "just send me the code" means cloning a repo. This page is the short version you wish someone had handed you before that moment.
What you get out of this page
You'll be able to start a new project, commit your work, branch for a demo or customer, push to GitHub, and open a pull request. That's enough Git to do your job without being the team's Git expert.
Not comfortable with Git on the command line? Let the Agent drive.
Every command on this page can be run by Cursor's Agent. A good starting prompt:
"Commit my current changes with a clear message, push the branch to GitHub, and open a pull request targeting
main."
The Agent walks through git status, git add, git commit, git push, and gh pr create with your approval. Read the steps below so you understand the workflow.
The mental model
Git is a tracker. Every time you save a snapshot (a "commit"), Git remembers exactly what the files looked like. You can jump back to any snapshot, branch off a snapshot to try something new, and merge branches back together.
GitHub is the place you push those snapshots so other people can see them. GitHub and Git are separate tools. Git runs on your laptop. GitHub is a service.
Three things matter in practice:
- Commits are snapshots. Small, frequent commits are easier to work with than giant ones.
- Branches are parallel histories. One per demo, per customer, or per experiment.
- Remotes are other copies of the repo (like the one on GitHub) that you push to and pull from.
The setup you only do once
Install Git and the GitHub CLI
Git is already installed if you followed Environment Setup or What If I Use Windows?. Install the GitHub CLI on top:
brew install gh # macOS
sudo apt install gh # Ubuntu / WSLConfigure your identity
git config --global user.name "Jane Doe"
git config --global user.email "jane.doe@salesforce.com"
git config --global init.defaultBranch main
git config --global pull.rebase falseLog in to GitHub from the CLI
gh auth loginPick SSH, follow the prompts, and gh will set up your SSH key against your GitHub account. From here on, git push and gh both "just work."
The day-to-day loop
Almost all your Git work is the same six commands.
Turn an existing Salesforce DX folder into a Git repo:
cd my-awesome-project
git initAdd a .gitignore so you don't commit garbage. A sensible starter for a Salesforce DX project:
# Salesforce
.sfdx/
.sf/
**/*.log
# Node
node_modules/
npm-debug.log
.env
# macOS / Windows cruft
.DS_Store
Thumbs.db
# Editor
.vscode/
.idea/First commit:
git add .
git commit -m "Initial scaffold of ACME POC"git status # what has changed?
git diff # what did I change, exactly?
git add force-app # stage one folder
git add . # or stage everything
git commit -m "Add triage agent topics and actions"Commit messages for SE work are most useful when they describe the why, not the what. "Add lookup from Case to Asset" is fine. "Fix ACME demo scenario where cases from gold customers route to a different queue" is better.
Every demo, customer, or experiment gets its own branch:
git checkout -b acme-poc-triage-agent
# ... work, commit, work, commit ...
git checkout main # switch back to the trunk
git checkout acme-poc-triage-agent # back to the branchBranching is cheap. When in doubt, branch. If the demo goes sideways, you can throw the branch away without touching main.
Create a repo from the CLI and push in one shot:
gh repo create acme-poc --private --source=. --pushOr, if the GitHub repo already exists:
git remote add origin git@github.com:yourorg/acme-poc.git
git push -u origin mainThe -u tells Git to remember this remote branch as the default upstream, so future git push with no arguments "just works."
When you're ready to hand something off or have someone review:
git push -u origin acme-poc-triage-agent
gh pr create --title "Triage agent for ACME" --body "POC build for the Spring rollout. See AGENTS.md for context."gh pr create opens an editor for the title and body if you don't pass them inline. After the PR is open, gh pr view --web pops the browser to the PR page.
Patterns that map to your actual SE workflow
"Resetting the demo org" via main
If your main branch is the last known good state of the demo, resetting a demo org becomes:
git checkout main
sf project deploy start --target-org demo
./scripts/reset.sh # re-seed mock data, reassign perm sets, etc.Whatever experimental thing you did during the last rehearsal stays on its branch, and main is your safe fallback.
One branch per customer conversation
After a discovery call, spin a branch for the ideas that came out of it:
git checkout -b acme-discovery-2026-04-22Build the agent, record the demo, open a PR back to main when it's ready to show. The branch name and PR description become free documentation of when, why, and for whom the work happened.
Sharing a POC with a partner
Create a private repo on the customer's or partner's GitHub org and push:
gh repo create acme-corp/poc-triage --private --source=. --pushAdd the partner's GitHub users as collaborators, make sure your .gitignore excludes anything you don't want to share, and verify with git ls-files that no secrets slipped through.
What should never be committed
Get into the habit of running git status before every commit and eyeballing the list. Things that should never end up in a commit:
.envor any other file holding secrets.- Your authenticated
sfconfig (.sf/config.jsonif it holds tokens). - Retrieved
Profilemetadata from a customer sandbox. - Anything under
.sfdx/(scratch org state). - Screenshots of customer data.
- Customer data in general, including CSV exports, JSON dumps, and SOQL result snapshots.
Your .gitignore prevents most of this. Read Security & Data Handling for the full list.
When something goes wrong
A handful of "oh no" moments and how to get out of them:
"I committed something I shouldn't have"
If you haven't pushed yet:
git reset HEAD~1 # unstage the last commit, keep the changes locally
# fix it, then commit againIf you already pushed, and the secret is the problem, rotate the secret first, then remove the file from history with git filter-repo or BFG. Don't just delete the file in a new commit. Old commits still contain it.
"I'm on the wrong branch"
git stash # park your uncommitted changes
git checkout correct-branch
git stash pop # bring them back"I deleted a file and need it back"
If you haven't committed yet:
git checkout -- path/to/fileIf you committed the deletion:
git checkout HEAD~1 -- path/to/file"The agent broke everything"
See Cursor Fundamentals for Cursor's checkpoint restore, which is faster than Git for in-session undo. For anything older, Git:
git log --oneline # find the good commit
git reset --hard <sha> # dangerous: wipes uncommitted changes tooUseful Git habits for SE work
- Commit before any long agent run. If the agent misfires,
git restore .puts you back. - Branch per demo. Cheap insurance.
- Small commits. Easier to review, easier to revert.
- Descriptive PR bodies. Your future self and your implementation partner will thank you.
- Keep
maindeployable. Ifmainis always the last known good state, resetting a demo becomes one command.
What to do next
- Lock down what leaks outside the repo with Security & Data Handling.
- Make deploys safer with Source Tracking &
.forceignore. - Automate repeated patterns with Rules & AGENTS.md.