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:
cd my-project
git init
You will see something like this:
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:
rm -rf .gitThat 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:
git config --global init.defaultBranch mainOr set it per repository at init time (same 2.28+ feature):
git init --initial-branch=main # short: git init -b mainOn 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:
# 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:
git statusEverything will show as untracked. Stage it all (your .gitignore is already excluding what should not go in):
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:
git commit -m "Initial commit"If this is a fresh machine, Git may stop you with an error before it lets you commit:
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:
git remote add origin git@github.com:your-username/my-project.gitOr with HTTPS:
git remote add origin https://github.com/your-username/my-project.gitConfirm it took:
git remote -vorigin 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.
| SSH | HTTPS | |
|---|---|---|
| URL form | git@github.com:user/repo.git | https://github.com/user/repo.git |
| Authentication | SSH key pair | Personal access token |
| One-time setup | Generate a key, add the public half to GitHub | Create a token, let a credential helper cache it |
| Pushes after setup | No prompt | No prompt (token cached) |
| Works behind strict firewalls | Sometimes blocked on port 22 | Usually 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:
git push -u origin mainThe -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:
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
maindirectly; 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,
mainonly 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
mainonly 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:
- Git branching explained for working on features without touching
main. - Git workflows for teams once more than one person is involved.
- How to add Git to an existing project for the other common case: a folder of code you wrote before setting up Git.
- Merge vs rebase when you start collaborating for the integration-strategy decision once you are pulling in other people's work.
- How forking compares to starting fresh if you are unsure whether to init, clone, or fork.
FAQ
Sources
Authoritative references this article was fact-checked against.
- git-init, official Git documentationgit-scm.com
- Pro Git: Recording Changes to the Repositorygit-scm.com
- About protected branches, GitHub Docsdocs.github.com





