Git is a tool that records snapshots of your project over time, so you can see what changed, undo mistakes, and work with other people without overwriting each other. To start using it you install Git, tell it who you are with git config, run git init in a folder, then stage and commit your files. That is the whole loop, and the rest of this guide walks through it slowly.
If you have never used version control before, the hardest part of Git is not the commands. It is the mental model. Once the model clicks, the commands stop feeling arbitrary. So I am going to start there.
The mental model: four places your code lives
Most Git confusion comes from not knowing where your files are at any moment. Git moves your work through four distinct places:
- Working directory: the actual files on disk that you edit in your editor. This is the only place that looks normal in your file browser.
- Staging area (also called the index): a holding area where you gather the exact changes you want in your next snapshot.
- Repository (the local
.gitfolder): the permanent history of committed snapshots, stored on your own machine. - Remote: a copy of the repository hosted somewhere else (GitHub, GitLab, your own server) that you and your teammates push to and pull from.
Work flows in one direction most of the time:
working directory → staging area → local repository → remote
(edit) (git add) (git commit) (git push)You edit files in the working directory. You pick which changes to include with git add, which moves them to the staging area. You take a snapshot of the staging area with git commit, which writes it into your local repository. Finally you git push to send those commits to the remote.
The staging area is the part beginners skip past, and it is the part that gives Git its precision. It lets you commit some of your changes and leave the rest for the next commit. I wrote a full breakdown in the Git staging area explained, because it is worth understanding properly rather than treating git add . as a magic word.
Installing Git
You probably already have Git. Check first:
git --versionIf you see a version number (anything 2.x is fine), skip ahead. If the command is not found, install it.
macOS: the easiest path is Homebrew:
brew install gitIf you have Xcode Command Line Tools installed, you already have a Git, but the Homebrew one stays more current.
Windows: download the installer from git-scm.com/download/win. It ships Git Bash, a terminal that behaves like Linux, which is what every tutorial (including this one) assumes. One thing to know up front: in Windows PowerShell, curl is an alias for Invoke-WebRequest, not the real curl, so when a guide tells you to run curl, use Git Bash or call curl.exe.
Linux (Debian/Ubuntu):
sudo apt update && sudo apt install gitOn Fedora it is sudo dnf install git; on Arch, sudo pacman -S git. Re-run git --version afterward to confirm.
First-time setup: tell Git who you are
Every commit records an author name and email. If you skip this, your very first commit fails with Please tell me who you are. Set it once, globally, and you never deal with it again:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"Use the same email here as on your GitHub account so your commits link to your profile. While you are at it, set a couple of sensible defaults:
git config --global init.defaultBranch main
git config --global pull.rebase falseThe first makes new repositories start on a branch called main instead of the older master. The second picks a clear default for what git pull does when your branch and the remote have both moved, which heads off the divergent-branches reconcile message. Confirm what Git recorded:
git config --listIf you ever see the wrong name on a commit, the fix lives in my note on the "Please tell me who you are" error.
Your first repository
Make a folder, go into it, and turn it into a Git repository:
mkdir hello-git
cd hello-git
git initgit init creates the hidden .git folder. That folder is the repository: it holds your entire history. Delete it and the folder goes back to being an ordinary directory with no version control. (Running Git commands outside such a folder is what triggers fatal: not a git repository, covered in the "not a git repository" fix.) The same git init works for adding Git to a folder that already has code, not just a fresh empty one.
Now create a file and check the status:
echo "# Hello Git" > README.md
git statusYou will see something like:
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)git status is the command you will run more than any other. It tells you which place each change is sitting in: untracked (Git does not know about it yet), staged (ready for the next commit), or modified-but-not-staged.
Your first commit
Move the file into the staging area, then snapshot it:
git add README.md
git commit -m "Add README"git add stages the file. git commit writes the staged snapshot into your repository with the message you passed. Run git status again and it reports a clean working tree, then look at the history:
git log --onelinea1b2c3d (HEAD -> main) Add READMEThat short string is the commit hash, a unique fingerprint for this snapshot. HEAD is just Git's word for "the commit you are currently sitting on."
A few habits worth forming on day one:
- Commit small, related changes together, not a giant dump at the end of the day.
- Write messages that describe why, in the present tense ("Fix login redirect", not "fixed stuff"). I keep a longer list of commit message conventions.
- Run
git statusbefore you commit so you know exactly what you are about to capture.
If your first commit captures the wrong thing or a bad message, you are not stuck. Undoing the last commit is a one-liner, and you almost never lose work doing it.
Connecting to a remote and pushing
So far everything lives only on your laptop. To back it up and share it, push to a remote. Create an empty repository on GitHub (no README, so it does not conflict with yours), then connect it:
git remote add origin git@github.com:your-username/hello-git.git
git branch -M main
git push -u origin mainorigin is the conventional name for your main remote. The -u flag links your local main to the remote main so that future pushes are just git push with no arguments. Skip the -u and your next push complains that the current branch has no upstream branch, which I cover in the no-upstream-branch fix. This flow is for a repo you created locally; if you are instead joining a project that lives on GitHub already, the path is the inverse, cloning a project that already exists.
The URL I used above is the SSH form (git@github.com:...). The other option is HTTPS (https://github.com/...). They behave the same once set up; they differ in how you authenticate. The short version: SSH uses a key you generate once, HTTPS uses a token. GitHub stopped accepting account passwords for Git over HTTPS in 2021, so if you try to push with your password you hit Support for password authentication was removed, which is why GitHub password pushes now fail. To go the SSH route, generate the SSH key first, then follow adding an SSH key to GitHub, or read the full comparison in SSH vs HTTPS remotes.
What not to commit
Some files should never go into Git: secrets, dependency folders, build output, editor junk. You tell Git to ignore them with a .gitignore file. A minimal one for a Node project:
node_modules/
.env
.DS_Store
dist/Add that file, commit it, and Git stops nagging about everything it lists. The two rules I care about most: never commit node_modules (it is huge and reproducible from your lockfile), and never commit a .env or any other file with credentials. A leaked secret in your history is genuinely dangerous, as the exposed .git directory attack shows, and getting one back out is a chore covered in removing a secret from Git history. Set up the ignore file early; the full reference is how to use .gitignore.
The everyday loop
Once the repo is connected, your normal day looks like this:
git pull # get the latest from the remote
# ... edit files ...
git add . # stage your changes
git commit -m "..." # snapshot them
git push # send them upThat is genuinely most of Git. Everything else is for when something goes sideways or you want more control.
How pull, fetch, add, and commit relate
A quick reference for the four commands you will reach for constantly:
| Command | Which place it touches | What it does |
|---|---|---|
git add | working directory → staging | Selects changes for the next commit |
git commit | staging → local repository | Records a permanent snapshot locally |
git push | local repository → remote | Uploads your commits to the remote |
git fetch | remote → local repository | Downloads remote commits without changing your files |
git pull | remote → working directory | fetch plus merging the changes into your branch |
The fetch vs pull distinction trips up everyone at first: fetch is the safe "just show me what's new" and pull is "show me and apply it." I unpack it in git pull vs git fetch.
Where to go next: the rest of the series
This page is the trailhead. Once the basic loop feels natural, branch out into the specific topics below. They are written to be read in any order, as you hit the need for each one.
Core concepts
- Git branching explained: work on features in isolation without breaking
main. - The Git staging area explained: why
git addexists and how to use it precisely. - How to use .gitignore: keep junk and secrets out of your history.
Undoing things (you will need these)
- How to undo the last commit
- git reset vs git revert: the two ways to "undo," and when each is right.
- How to discard local changes
- How to use git stash: shelve unfinished work to switch tasks.
- How to recover lost commits with git reflog: the safety net almost no beginner knows about.
Working with others
- How to resolve merge conflicts
- git merge vs git rebase
- How to create a pull request
- Fork vs clone in Git and how to sync a fork with upstream.
- Git workflows for teams: GitHub Flow, Git Flow, and trunk-based, compared.
Common errors, fixed
- failed to push some refs
- Permission denied (publickey)
- src refspec main does not match any
- refusing to merge unrelated histories
Pick the topic that matches whatever Git just did to you, and come back here when you need the next piece.
Sources
Authoritative references this article was fact-checked against.
- Pro Git: Getting Started, About Version Controlgit-scm.com
- git-config, official Git documentationgit-scm.com
- Set up Git, GitHub Docsdocs.github.com





