NK

Search

Search pages, projects, posts, components, and icons

All articles
Engineering13 min read

Git and GitHub for Beginner Developers

The mental model that makes Git make sense, the eight commands you actually need, and how to undo the four mistakes everybody makes in their first month.

gitgithubbeginnersworkflow

Git is not hard because the commands are complicated. It is hard because most tutorials teach the commands without the model underneath, so you end up with a list of spells: type this to save, type that to upload, and if something goes wrong, delete the folder and clone it again.

Everybody has deleted the folder and cloned it again. It works, and it means you do not yet have the model.

This is the model, then the eight commands that cover nearly everything, then how to get out of the four situations that will otherwise cost you an evening.

Glossary

Everything this post uses, defined before it is used. Skip it if the terms are already familiar, or come back when one of them trips you up.

The one sentence the rest of this post expands: Git records a series of snapshots of your project along with why each one was made, and every command below is either making a snapshot, moving between them, or undoing one.

Terms

TermMeaning
RepositoryA project Git is tracking, including its whole history. Usually shortened to "repo".
CommitOne saved snapshot of the project, with a message saying why.
Working directoryYour actual files on disk, right now.
Staging areaThe list of changes you have marked as belonging in the next commit.
BranchA movable name pointing at a commit. Work happens on one without disturbing others.
mainThe branch a project treats as its real, working version. Older projects call it master.
RemoteA copy of the repository somewhere else, usually on GitHub.
originThe conventional name for the main remote. Just a nickname for a URL.
CloneCopying a remote repository onto your machine, history included.
PushSending your commits to the remote.
PullFetching the remote's commits and merging them into your branch.
FetchDownloading the remote's commits without touching your files.
MergeCombining two lines of history into one.
Merge conflictTwo changes to the same lines, where Git refuses to guess and asks you.
RebaseReplaying your commits on top of another branch, producing a straight history.
Pull requestA GitHub request to merge your branch, with review and discussion attached.
HEADWhere you are right now. HEAD~1 means one commit before that.
StashA temporary shelf for uncommitted changes.
.gitignoreA file listing paths Git should never track, such as secrets and build output.
Rotate a keyReplacing a leaked secret with a new one so the leaked value is worthless.
RevertMaking a new commit that undoes an earlier one, leaving history intact.
ResetMoving your branch pointer backwards, optionally discarding work.

Abbreviations

ShortFull formIn plain words
Gitnot an abbreviationThe program on your machine that records the history
PRPull RequestThe GitHub page where a branch is reviewed before merging
SHASecure Hash AlgorithmThe long identifier Git gives each commit, usually shown as the first seven characters
CIContinuous IntegrationAutomated checks that run on every push
APIApplication Programming InterfaceA service other code talks to, usually needing a secret key
CLICommand-Line InterfaceTyping commands in a terminal rather than clicking buttons
FAQFrequently Asked QuestionsThe question section near the end

Git and GitHub are different things

Git is a program on your computer that records snapshots of your project. It works with no internet connection and no account anywhere. It is the thing doing the actual work.

GitHub is a website that hosts copies of Git repositories, and adds things Git itself does not have: pull requests, issues, code review, permissions, CI.

You can use Git without GitHub forever. You cannot use GitHub without Git. When something breaks, knowing which of the two you are fighting is half the diagnosis.

The model: three places your code lives

Nearly every confusing Git moment comes from not knowing which of these three places a change is currently in.

An analogy that keeps working later on: your working directory is the desk, the staging area is the envelope you are filling, and the repository is the filing cabinet. Editing a file changes the desk. git add puts a page in the envelope. git commit seals the envelope and files it, dated and labelled, forever.

working directory  ->  staging area  ->  repository
   (your files)         (git add)        (git commit)

Working directory is your actual files, as they are on disk right now.

Staging area is a list of changes you have marked as belonging in the next commit. This is the part with no equivalent in Google Docs or Dropbox, which is why it feels arbitrary at first. It exists so you can commit some of your changes and not others.

Repository is the permanent history: the sequence of commits, each a full snapshot of the project with a message explaining it.

One command shows you all three at once, and you should run it constantly:

git status

Beginners run git status when something is wrong. Experienced developers run it before and after almost every command. It is the cheapest habit in software.

Starting out

Set your identity once

Every commit records who made it. Do this before your first commit or you will have commits attributed to nobody:

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

Start a repository

Either turn an existing folder into one:

cd my-project
git init

Or copy an existing one from GitHub:

git clone https://github.com/username/repo-name.git

Make your first commit

git status                    # see what changed
git add index.html            # stage one file
git add .                     # or stage everything
git commit -m "Add landing page"

A note on that message, because it is the part beginners treat as a formality and seniors treat as documentation. Write what the commit does, in the imperative, as though completing the sentence "this commit will...":

git commit -m "Fix crash when profile image is missing"   # good
git commit -m "changes"                                   # useless in a week
git commit -m "asdf"                                      # you know who you are

You are writing for the person who runs git log in six months trying to work out when a bug appeared. That person is usually you.

Ignore what should not be committed

Create a .gitignore file before your first commit:

node_modules/
.env
.DS_Store
build/

Never commit secrets. An API key pushed to GitHub is compromised even if you delete it in the next commit, because the history still contains it and bots scan public repositories within minutes. If it happens, rotate the key immediately. Removing it from history is the second step, not the first.

Working with GitHub

Connect a local repository to a remote

git remote add origin https://github.com/username/repo-name.git
git push -u origin main

origin is just a name for the remote URL, by convention the main one. The -u sets it as the default, so future pushes are one word:

git push

Going deeper: getting other people's changes

While you were working, other people were committing too. Getting their work is two separate ideas that one command quietly does together, and separating them is what stops surprise merges.

git pull

git pull is two operations: fetch the remote's commits, then merge them into your branch. When you want to look before merging:

git fetch
git log HEAD..origin/main --oneline   # what came in that you do not have

Branches, which are the actual point

A branch is a movable pointer to a commit. Creating one costs nothing, which is why Git culture creates them freely.

The reason to branch is that main should always work. Your half-finished feature does not belong there.

git switch -c feature/user-profile   # create and switch to it
# ... work, commit, work, commit ...
git push -u origin feature/user-profile

Then on GitHub, open a pull request: a request to merge your branch into main, with a place for others to review it first. This is where GitHub adds something Git does not have. Git can merge. Only GitHub gives you the conversation, the review and the checks around it.

Switching between branches:

git switch main
git switch feature/user-profile
git branch                    # list local branches

You may see git checkout in older tutorials. It still works, but it does two unrelated jobs (switching branches and restoring files), which is exactly the confusion git switch and git restore were introduced to fix.

The four things that will go wrong

1. You committed to the wrong branch

You did the work on main and meant to be on a branch. Nothing is lost:

git branch feature/thing        # bookmark the current commit
git reset --hard origin/main    # move main back to the remote's state
git switch feature/thing        # your work is here

2. You need to undo the last commit

Three different situations, three different answers.

Keep the changes, undo the commit (most common):

git reset --soft HEAD~1

Keep the changes but unstage them too:

git reset HEAD~1

Throw the changes away entirely:

git reset --hard HEAD~1

--hard is the only one that destroys work. Be sure before you type it.

If the commit is already pushed and others may have pulled it, do not rewrite history. Make a new commit that undoes it:

git revert <commit-hash>

3. You have a merge conflict

A conflict means two people changed the same lines and Git will not guess. It is not an error, it is a question.

Git marks the file:

<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> feature/increase-timeout

Above the ======= is your version, below is theirs. Edit the file to what it should actually be, delete all three marker lines, then:

git add config.js
git commit

The mistake beginners make is deleting one side without reading it. Both sides were somebody's intention. Sometimes the right answer is neither.

4. You have changes but need to switch branches

git stash              # put changes aside
git switch main
# ... do the urgent thing ...
git switch feature/thing
git stash pop          # bring them back

Stashes are easy to forget about. git stash list shows them, and a stash from three weeks ago is usually best deleted rather than applied.

Reading history

git log --oneline --graph --all -20

That gives a compact, visual view of the last 20 commits across all branches, and is worth an alias.

To find when a specific line changed and why:

git blame src/app.js

blame is badly named. Its real use is archaeology: you find a strange line, learn which commit introduced it, and read the message explaining why. Which is the actual reason to write good commit messages.

The eight commands that cover most days

git status                  # where am I, what changed
git add <file>              # stage a change
git commit -m "message"     # record staged changes
git push                    # send commits to the remote
git pull                    # get commits from the remote
git switch -c <branch>      # start a branch
git log --oneline           # what happened recently
git diff                    # what exactly changed

Everything else is either rarer or a variation. If those eight are muscle memory, you can work on a team.

Key takeaways

  • Git is local. GitHub hosts it. Knowing which one you are fighting is half of any diagnosis.
  • Three places: working directory, staging area, repository. Most confusion is not knowing which one your change is in.
  • Run git status constantly. It is the cheapest habit in software.
  • Write commit messages for the person reading git log in six months. That person is usually you.
  • .gitignore before the first commit, and never commit secrets. A pushed key is compromised even after deletion.
  • Branch freely. They cost nothing, and main should always work.
  • Pull requests are GitHub, not Git. Git merges. GitHub adds the review.
  • Conflicts are questions, not errors. Read both sides before choosing.
  • --hard is the only reset that destroys work. Everything else is recoverable.

FAQ

What is the difference between git pull and git fetch?

fetch downloads the remote's commits without touching your working files. pull does that and immediately merges. Use fetch when you want to look first.

Should I use main or master?

main is the current default on GitHub and most new projects. Either works. Be consistent with whatever the repository already uses.

What is the difference between merge and rebase?

merge creates a commit joining two histories, preserving what actually happened. rebase replays your commits on top of another branch, producing a straight line. Learn merge first. Rebase is a sharper tool and rewrites history, which is dangerous on shared branches.

How do I undo git add?

git restore --staged <file>

The file keeps your changes, it is just no longer staged.

Do I need to commit every day?

Commit whenever a piece of work is coherent, not on a schedule. Small, focused commits are easier to review, easier to revert and easier to search.

Is the GitHub desktop app cheating?

No. Use whatever gets the work done. But learn the commands eventually, because every CI system, server and teammate's instructions assume them.

Conclusion

The shift that makes Git click is realising it is not a backup tool. It is a record of decisions. Each commit says: at this point, someone changed these lines, for this stated reason.

That reframing changes how you use it. You stop making one enormous commit at the end of the day and start making small ones that each mean something. You stop writing "update" and start writing what you did. You stop fearing branches, because a branch is just a name for a commit and names are cheap.

You will still get stuck. When you do: run git status, read what it says, and notice that it usually tells you the exact command to get out. Git's error messages have quietly become one of the better help systems in developer tooling, and almost nobody reads them.

References

Official documentation for the topics covered here.

Read more

New to the wider workflow? How I Build This Blog With MDX shows what a small real project's repository looks like in practice, including what belongs in version control and what does not.