TechEarl

How to Set Up Git for a New Project

Set up Git for a new project the right way: git init, a starter .gitignore, your first commit, creating the remote, pushing, and turning on branch protection.

Ishan Karunaratne⏱️ 10 min readUpdated
Share thisCopied
How to set up Git for a new project: git init, a starter .gitignore, the first commit, and pushing to a new remote

To set up Git for a new project, run git init inside your project folder, add a .gitignore so junk files never get tracked, then git add and git commit your first snapshot. Create an empty repository on GitHub, connect it with git remote add origin, and git push -u origin main. After the first push, turn on branch protection so nobody (including you) can force-push to main.

That is the whole sequence. The rest of this guide walks through each step, explains why each one matters, and points out the small mistakes that bite people on day one. If you are brand new to version control, start with Git for beginners first, then come back here when you have a real project to track. This guide assumes a fresh, empty folder; if you already have a folder full of code, see adding Git to an existing project for the ignore-first workflow that keeps junk and secrets out of the first commit.

Step 1: Initialize the repository with git init

Move into your project folder and turn it into a Git repository:

bash
cd my-project
git init
Initializing a Git repository and making the first commit in the terminal
Setting up a new Git project: init, add, commit, then log.

You will see something like this:

text
Initialized empty Git repository in /home/techearl/my-project/.git/

git init creates a hidden .git folder. That folder is the repository: it holds every commit, branch, and configuration value for this project. Delete it and you delete the history. Everything else in the folder is just your working files. There is no server, no account, and no network involved yet. This is a fully functional Git repository that lives entirely on your machine.

A common beginner mistake is running git init in the wrong place, usually one directory too high (your home folder, or a folder full of unrelated projects). Check where you are with pwd before you run it. If you do init the wrong folder, you can undo it safely by deleting the .git directory:

bash
rm -rf .git

That removes the repository and leaves your files untouched.

Set the default branch name to main

Older versions of Git named the first branch master. Modern Git and every major host now default to main. From Git 2.28 (July 2020) onward you can control the initial branch name. Set it once for every new repo:

bash
git config --global init.defaultBranch main

Or set it per repository at init time (same 2.28+ feature):

bash
git init --initial-branch=main   # short: git init -b main

On Git before 2.28 there is no default-branch config to set; just rename after init with git branch -m master main.

Setting this now saves you from a rename later, and it keeps your local branch name matching what GitHub expects.

Step 2: Add a .gitignore before your first commit

This is the step people skip, and then regret. A .gitignore file tells Git which files to never track: build output, dependency folders, secrets, editor cruft, OS noise. Add it before the first commit so those files never enter the history in the first place. Once a file is committed, removing it later is more work, and if it was a secret, the secret is still recoverable from history forever.

Create a .gitignore in the project root. A reasonable starter for a Node project:

bash
# dependencies
node_modules/

# build output
dist/
build/
.next/

# environment and secrets
.env
.env.local

# logs
*.log

# OS and editor noise
.DS_Store
Thumbs.db
.idea/
.vscode/

The patterns are matched against paths relative to the repository root. A trailing slash like node_modules/ matches a directory; *.log matches any log file at any depth. GitHub maintains language-specific templates at github.com/github/gitignore, and most editors will scaffold one for you. I go deeper on the syntax, the negation rules, and the "I already committed it" recovery in how to use .gitignore.

The single most important entry is .env (or whatever holds your credentials). If you commit and push a secret, treat it as leaked the moment it lands on the remote. Rotate the credential, then scrub it out of history. I wrote a full procedure in how to remove a secret from Git history, and the related risk of a publicly exposed repository in the exposed .git directory attack.

Step 3: Stage and make the first commit

Check what Git sees first:

bash
git status

Everything will show as untracked. Stage it all (your .gitignore is already excluding what should not go in):

bash
git add .

git add moves your changes into the staging area, which is the holding zone for your next snapshot. It does not save anything permanently yet. If you want to be deliberate about what goes in, stage files one at a time instead of git add .. The staging area is the part of Git that gives you that control, and it is worth understanding properly; I broke it down in the Git staging area explained.

Now take the snapshot:

bash
git commit -m "Initial commit"

If this is a fresh machine, Git may stop you with an error before it lets you commit:

text
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

That just means Git does not know who to credit for the commit. Set your identity and run the commit again. The fix and the reasons behind it are in how to fix 'Please tell me who you are'.

A good first commit message is plain and present-tense. "Initial commit" is fine for the very first one; after that, write messages that say what changed and why. If you realize you committed the wrong files or a bad message, you can undo that first commit before you push. I keep a short set of rules in Git commit message best practices.

Step 4: Create the remote and connect it

So far everything is local. To back it up and share it, you need a remote: a hosted copy of the repository. Create an empty repository on GitHub (or GitLab, or your own server). Empty is the key word: do not let GitHub add a README, a license, or a .gitignore for you. If it does, the remote already has a commit your local repo does not, and your first push will be rejected with a divergence error. (If that happens to you, here is how to fix 'failed to push some refs'.)

Once the empty repo exists, GitHub shows you its URL. Connect it as your origin remote. With SSH:

bash
git remote add origin git@github.com:your-username/my-project.git

Or with HTTPS:

bash
git remote add origin https://github.com/your-username/my-project.git

Confirm it took:

bash
git remote -v
text
origin  git@github.com:your-username/my-project.git (fetch)
origin  git@github.com:your-username/my-project.git (push)

SSH or HTTPS?

The two URLs do the same job; they differ in how you authenticate. GitHub removed support for plain account passwords over HTTPS in 2021, so HTTPS now uses a personal access token, and SSH uses a key pair you generate once.

SSHHTTPS
URL formgit@github.com:user/repo.githttps://github.com/user/repo.git
AuthenticationSSH key pairPersonal access token
One-time setupGenerate a key, add the public half to GitHubCreate a token, let a credential helper cache it
Pushes after setupNo promptNo prompt (token cached)
Works behind strict firewallsSometimes blocked on port 22Usually fine (port 443)

If you went the SSH route and do not have a key yet, first create an SSH key, then follow add an SSH key to GitHub. The full trade-off is in Git SSH vs HTTPS remotes. If your push fails with a Permission denied (publickey) message, your key is not set up correctly; here is how to fix that.

Step 5: Push and set the upstream

Send your commits to the remote and link your local branch to it in one go:

bash
git push -u origin main

The -u (short for --set-upstream) is the important part. It tells Git that your local main tracks origin/main. After this single push, plain git push and git pull know where to go, with no arguments needed. Skip the -u and you will eventually hit:

text
fatal: The current branch main has no upstream branch.

That is harmless and easy to clear; see the current branch has no upstream branch. Setting -u on the first push avoids it entirely.

One more first-push gotcha: if you committed your files but your branch is somehow empty, or you renamed the branch, you might see src refspec main does not match any. That means there is no main branch with a commit to push; the src refspec does not match any fix covers it.

After this, refresh the repository page on GitHub and your files are there.

Step 6: Protect the main branch

Now that the project lives on GitHub, lock down the branch that matters. Branch protection stops anyone, including you on a bad day, from force-pushing over history or deleting main. On a solo project it is a safety net; on a team it is essential.

In the GitHub repository, go to Settings → Branches → Add branch protection rule (newer accounts call these rulesets), target main, and turn on the rules that fit your project. The ones I reach for on almost every repo:

  • Require a pull request before merging. Nothing lands on main directly; changes come in through a pull request. This alone catches a huge amount of "oops, committed straight to main" mistakes.
  • Require status checks to pass. If you have CI, main only accepts code that builds and passes tests. Wiring that up for a Node project is covered in push-to-deploy with GitHub Actions.
  • Block force pushes. This is the rule that protects your history. A force push can silently rewrite or erase commits; turning it off means the history on main only ever moves forward.

The protection lives on the remote, not in your local repo, so it applies to everyone who pushes. I cover the full set of options and the reasoning in how to protect your main branch on GitHub.

You are set up. What next?

At this point you have a tracked project, a backed-up remote, and a protected main. The day-to-day loop from here is: create a branch, make changes, commit, push, open a pull request. A few good next reads:

FAQ

Sources

Authoritative references this article was fact-checked against.

TagsSet Up Git for a ProjectGitVersion ControlGitHubDevOps

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Tech Architect · Software Engineer · AI/DevOps

Tech architect and software engineer with 20+ years building software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Currently Chief Technology Officer at a healthcare tech startup, which is where most of these field notes come from.

Keep reading

Related posts

How to Use Git with WordPress

How to put a WordPress project under Git: what to track vs ignore, a ready .gitignore, version-controlling just your theme or plugin, and deploy options.

How to Use .gitignore (with Examples)

A practical guide to .gitignore: pattern syntax, per-repo vs global ignore, ready-made templates, and the gotcha that trips everyone up - already-tracked files keep showing up.