How to use Git and GitHub for version control (without losing your mind in the first week)
Someone asked me last month why their code kept disappearing. Turned out they were saving over the same file, day after day, with names like final_v2_REALLY_final.py. I laughed. Then I remembered I did exactly the same thing for the first two years of my career.
Version control is what happens when you stop renaming files and start letting a tool remember every change for you. Git is that tool. GitHub is where you put those changes so other people (and future-you) can find them. Learning how to use Git and GitHub for version control is less about memorizing commands and more about building one habit: commit often, push when it matters.
Key takeaways
- Git runs on your machine; GitHub is a remote host for your repositories. They are two different things. Confusing them is the #1 beginner mistake.
- You only need about six commands for 90% of daily work:
init,clone,add,commit,push,pull. - Branches are cheap. Use them for every change bigger than a typo fix.
- Merge conflicts are not errors. They are Git asking you to make a decision.
- A
.gitignorefile saves you from committing secrets, logs, and dependency folders you will regret later. - If you push something sensitive by accident, rotate the key immediately. Deleting the commit is not enough.
Git vs GitHub: what is actually the difference?
Git is a distributed version control system. It was written by Linus Torvalds in 2005 to manage the Linux kernel, and it has been the default ever since. GitHub launched three years later as a hosting service built on top of Git.
Here is the distinction that matters in practice. Git works offline. Every commit, branch, and history lookup happens locally on your disk. GitHub is a website that stores a copy of your repository and adds collaboration features on top: pull requests, issues, code review, actions.
Is GitHub version control?
No. GitHub is a platform for hosting Git repositories. The version control itself is Git. You can run Git with zero GitHub account and never touch the internet. GitHub just gives your repository a home that other people can reach.
Think of it this way: Git is the engine, GitHub is the garage where you park the car so your teammates can borrow it.
Why the distributed part matters
Older systems like SVN kept one central server. If that server went down, nobody could commit. Git gives every clone a full copy of the history, which means:
- You can commit on a plane with no wifi
- Recovering from a corrupted remote is trivial because any clone is a backup
- Branching is fast enough that you stop thinking about whether it is "worth it"
That last point changed how I work. On SVN, I avoided branches because merging back was a small nightmare. On Git I create one for a single-line fix without hesitating.
Your first repository, step by step
Install Git from the official site, then open a terminal and check it works:
git --versionshould print something likegit version 2.x.x- Set your identity once:
git config --global user.name "Your Name"andgit config --global user.email "[email protected]"
Skip that second step and your commits will be attributed to a ghost. I have seen this trip people up for weeks.
Start local, then connect to GitHub
In an empty project folder:
git initturns the folder into a repository- Create a file, then
git add .to stage it git commit -m "first commit"records the snapshot
Now create an empty repository on GitHub. Do not let it initialize with a README, or you will have two unrelated histories and your first push will be rejected. Connect the two:
git remote add origin [email protected]:user/repo.gitgit branch -M maingit push -u origin main
The -u flag links your local branch to the remote one, so future pushes are just git push.
SSH keys versus HTTPS
You have two ways to authenticate. HTTPS asks for a token every so often. SSH uses a key pair you generate on your machine, and after the initial setup, it never asks again.
Generate the key with ssh-keygen -t ed25519 -C "[email protected]", then paste the contents of the public file into GitHub under Settings → SSH and GPG keys. I resisted this for a year because it sounded complicated. In reality it took four minutes and removed a daily friction point.
The daily workflow you will actually use
Most tutorials dump twenty commands on you at once. Here is what day-to-day work looks like in reality:
| Task | Command | How often I run it |
|---|---|---|
| See what changed | git status | Constantly |
| Stage a specific file | git add path/to/file | Most days |
| Save a snapshot | git commit -m "message" | 5-15 times a day |
| Send to GitHub | git push | End of each work block |
| Get teammates' changes | git pull | Start of each session |
| Create a branch | git switch -c feature/x | Every new task |
That is roughly it. Everything else is recovery from a mistake or a collision with someone else's work.
Commit messages: short, imperative, honest
Write "fix login redirect loop" not "fixed stuff". Six months from now, when you are hunting for the change that broke a feature, the message is the only clue you have. I read through my own commit history from 2022 last week and could not tell what half of them did. That is a failure of past-me, not of Git.
Set up .gitignore before your first commit
A .gitignore file tells Git which paths to never track. Add it early, because removing a secret from history is painful.
- Node projects:
node_modules/ - Python:
__pycache__/,*.pyc,.venv/ - Anything holding credentials:
.env,*.pem - Your editor's junk:
.vscode/,.DS_Store
If a file is already tracked, adding it to .gitignore does nothing. You have to git rm --cached it first.
Branches, merges, and the conflict everyone fears
A branch is a movable pointer to a commit. Creating one costs almost nothing, which is why the standard advice is: branch for everything.
A typical flow
git switch -c fix/payment-timeoutcreates and switches- Make your changes, commit them
git push -u origin fix/payment-timeout- Open a pull request on GitHub
- After review and merge, delete the branch locally and remotely
That last cleanup step is easy to forget. I once had a repository with 47 stale branches, most of them from features shipped months earlier. It made the branch list useless.
What a merge conflict really is
Git is not failing. It is refusing to guess. Two branches changed the same lines, and it wants a human decision.
Open the file, and you will see markers:
<<<<<<< HEADmarks your version=======separates the two>>>>>>> branch-namemarks the incoming version
Edit the file down to what you actually want, delete the markers, then git add and git commit. The first time feels scary. The tenth time it is just editing a text file.
The thing that made conflicts rare for me was pulling before starting work. Merging a day of divergence is annoying. Merging five minutes of divergence is trivial.
Stashing, undoing, and the mistakes you will make
You will commit to the wrong branch. You will push something you meant to keep local. These are survivable.
The three undo commands worth memorizing
git restore file.txtdiscards uncommitted changes to one filegit reset --soft HEAD~1uncommits the last commit but keeps the changes stagedgit revert <hash>creates a new commit that undoes an old one, which is the safe option on shared branches
Avoid git reset --hard on anything you have pushed. It rewrites history, and anyone who already pulled will have a bad afternoon.
Stashing what you are not ready to commit
Mid-feature, someone asks for an urgent fix. You are not ready to commit half-finished work. Run git stash, do the fix, commit it, then git stash pop to get your work back.
I learned this the hard way after committing a broken file to keep my work safe, then forgetting about it. The stash is cleaner.
CLI, VS Code, or a GUI: which should you use?
Honestly? Learn the command line first, then use whatever is fastest for you.
The CLI teaches you what is really happening. GUIs hide the mechanism, and when something goes wrong, you will not know how to fix it. But once you understand the model, tools like VS Code's built-in Git panel or a dedicated client will save you real time on routine staging and reviewing diffs.
| Interface | Best for | Weakness |
|---|---|---|
| Command line | Learning the model, scripting, any server | Less visual feedback |
| VS Code built-in | Everyday editing and staging | Occasional confusing state display |
| Dedicated GUI | Reviewing large diffs, history browsing | Hides the underlying commands |
Where most people go wrong
- Committing everything in one giant blob at the end of the day. Small commits are easier to revert and easier to review.
- Never pulling from the remote. You will eventually face a merge from hell.
- Committing
.envfiles. Rotate the credentials immediately if you do. - Treating branches as permanent. They are not meant to live forever.
- Using GitHub as backup without ever reading the diff. Version control only helps if you use it as one.
The habit that stuck for me was pulling first thing every morning. One command, twenty seconds, and it removed almost every painful merge I used to run into. Version control does not make you a better developer on its own. It just records the evidence, in order, so you can figure out what you did wrong and prove it to yourself. That is already worth the price of admission.