The Right Way to Set Up Your Salesforce SFDX Project with Git — No Conflicts, No Ref Errors

A definitive guide to setting up SFDX projects with Git that avoids the common push ref errors and conflicts that trip up even experienced Salesforce engineers

6 min readDevOps

"Do I create the Git repo first or the project first?"

"Why does Git throw push ref errors even though it's a brand-new project?"

These are classic setup confusions that trip up even experienced Salesforce engineers when working with SFDX source format and GitHub for the first time.

And almost always, people follow imprecise, conflicting steps.

They create the project locally, or they create the repo remotely first.

They try to push, and they hit ref errors.

They scramble around Git commands.

And they lose trust in the whole process.

The problem is not your tools. It's the way you start.

In this article, I'll show you the exact step-by-step process that works — clean, conflict-free, and safe for enterprise GitHub workflows.


The Two Wrong Patterns Most Engineers Unknowingly Follow (And Why They Fail)

Pattern 1: Local-first, then pushing to non-empty remote — ends in ref errors

  1. Engineer creates SFDX standard source format project locally in VS Code
  2. Initializes Git locally (git init)
  3. Adds metadata, commits locally
  4. Adds remote repo (which was already created with a README, .gitignore, etc. in enterprise GitHub)
  5. Tries to push:
git push origin main

Gets this error:

! [rejected] main -> main (fetch first) error: failed to push some refs to 'https://github.mycompany.com/team/salesforce-core.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again.

Root cause:

  • The remote has an initial commit (like README)
  • Your local has a different initial commit
  • Git refuses to fast-forward — it demands you first pull and merge, which leads to unwanted conflicts on day one

Pattern 2: Remote-first with README, cloned locally — leads to path confusion and push chaos

  1. Engineer creates new GitHub repo from enterprise GitHub portal
  2. Adds README during repo creation
  3. Clones the repo locally in VS Code
  4. Creates the SFDX project inside the cloned folder
  5. Tries to push metadata

Ends up seeing:

  • Confusion in source paths (force-app not showing properly)
  • Push errors when syncing metadata

Root cause: Cloning a repo that already has a README sets a remote baseline. When you create SFDX project inside the same folder, your local commits try to sit on top of a different commit history (from README), leading to ref errors and path confusions.


The Exact, Correct Sequence (Learned the Hard Way)

Here's the battle-tested sequence I follow, with no ambiguity.

1. Create an empty GitHub repo

  • Go to your enterprise GitHub (https://github.mycompany.com)
  • Create the repo
  • IMPORTANT: Do NOT add README, LICENSE, or .gitignore
  • Keep it completely empty

Why? This ensures remote is literally empty, ready to accept your local repo as the first push. You avoid all push ref errors right at the root.

2. Create local SFDX project in VS Code (standard source format)

  • Use SFDX: Create Project → Standard
  • Confirm project has force-app, sfdx-project.json
  • Double-check your folder is clean with only Salesforce standard project structure

3. Authorize to Production org

Use:

sfdx auth:web:login -r https://login.salesforce.com

Pull metadata (initial download) from Production, not Sandbox.

You can use VS Code Org Browser for that, or use commands from CLI for metadata types Org Browser may not support:

sfdx force:source:retrieve

Why Prod? You want your initial repo to have the latest clean metadata baseline from production. Engineers later will point to their Sandboxes, but this gives a single source of truth for the repo initialization.

4. Initialize Git locally

git init git branch -m main

Confirm current branch:

git branch --show-current

5. Add and commit all metadata

git add . git commit -m "Initial commit"

Optional (only if Git config is missing on your local machine):

git config user.email "you@yourcompany.com" git config user.name "Your Name"

6. Connect to your empty GitHub repo

git remote add origin https://github.mycompany.com/team/salesforce-core.git

Validate:

git fetch origin

7. Push your clean initial commit

git push origin main

Expected result: Clean push, no ref errors, no history mismatches. Your initial repo is now perfectly aligned between local and remote.


Why This Sequence Works

This approach eliminates the fundamental conflict between local and remote Git histories by:

  1. Starting with truly empty remote — no competing initial commits
  2. Building complete local state first — your metadata becomes the authoritative baseline
  3. Single direction of truth — local pushes to empty remote, establishing clean history

The key insight: Git conflicts arise from competing histories, not from the tools themselves. By controlling the initialization sequence, you eliminate the source of conflicts entirely.


Common Variations and When They Still Work

If you already have a non-empty remote repo:

# Clone the existing repo git clone https://github.mycompany.com/team/existing-repo.git cd existing-repo # Create SFDX project in a subdirectory or merge carefully # This requires more advanced Git knowledge to avoid conflicts

If you prefer GitHub CLI:

# Create empty repo via CLI gh repo create myorg/salesforce-project --private # Continue with steps 2-7 above

Next Steps: Setting Up Your Development Workflow

Once your repo is cleanly initialized, you'll want to establish:

  • Branch protection rules for your main branch
  • Pull request workflows for code review
  • CI/CD pipelines for automated deployment (this is where tools like Navceed excel)
  • Environment-specific configurations for sandbox development

The clean foundation from this setup process makes all subsequent automation more reliable and predictable.


Closing Thoughts

Getting the initial setup right saves hours of frustration later. The sequence above has worked consistently across enterprise environments, different GitHub configurations, and various team sizes.

Remember: the goal isn't just to get it working — it's to establish a clean, reproducible foundation that your entire team can build upon confidently.

Tags:sfdxgitsetupsalesforcegithubproject-setupdevops