Zum Inhalt springen
Home » Git Workflow for Beginners: From Chaos to Clean Commits

Git Workflow for Beginners: From Chaos to Clean Commits

Git Workflow for Beginners: From Chaos to Clean Commits

Here’s the thing nobody tells you when you start coding: learning a programming language is maybe 40% of the job. The other 60%? It’s tooling. And right at the top of that tooling list sits Git — the version control system that roughly 94% of developers use daily, and that you will absolutely butcher for the first six months. I know because I did.

I spent my first year with Git treating it like a fancy save button. git add ., git commit -m "stuff", git push. That was my entire workflow. Three commands, zero understanding. And it worked — right up until it didn’t.

Why Does Git Feel So Confusing at First?

Git feels confusing because it was built for the Linux kernel, not for you. Linus Torvalds created it in 2005 to manage thousands of contributors working on the most complex open-source project on the planet. The mental model it expects — staging areas, directed acyclic graphs, detached HEAD states — these are concepts designed for distributed systems engineers, not someone three months into their first bootcamp.

But here’s what changed everything for me: stop trying to understand Git from the bottom up. You don’t need to know how SHA-1 hashes work to write clean commits. You need a workflow. A set of habits you follow until they become muscle memory. The understanding comes later, almost by accident.

And with GitHub now hosting over 180 million developers across 630+ million repositories, you’re going to be collaborating through Git whether you like it or not. So let’s get your workflow sorted.

The Only Branching Strategy You Need Right Now

Use GitHub Flow. Forget everything else for now. I mean it. There are three major branching strategies people argue about online: GitFlow (overly complex, designed for scheduled releases), Trunk-Based Development (great but requires CI/CD maturity most beginners don’t have), and GitHub Flow. GitHub Flow wins for beginners because it has exactly one rule: main is always deployable, and everything else happens on feature branches.

That’s it. That’s the whole strategy.

You create a branch, you do your work, you open a pull request, someone reviews it (or you review it yourself if you’re solo), you merge. The branch gets deleted. Done. No develop branch, no release/v2.3.1 branches, no hotfix branches branching off of release branches. Just main and your feature branches.

Here’s what that looks like in practice:

git checkout -b feature/add-contact-form
# do your work, make commits
git push -u origin feature/add-contact-form
# open a PR on GitHub
# merge when ready
git checkout main
git pull
git branch -d feature/add-contact-form

I’ve been using this for years on personal projects and small teams. It scales surprisingly well up to maybe 8-10 developers. Beyond that you might want to look at trunk-based, but that’s a problem for future you.

Commit Messages: The Skill Nobody Practices

Your commit messages are a letter to your future self, and right now you’re writing them like someone who hates that person.

We’ve all done it. „fix bug.“ „update styles.“ „asdfasdf.“ „WIP.“ I once scrolled through a project history and found seventeen consecutive commits that just said „changes.“ Seventeen! From me! I was the problem!

The Conventional Commits specification exists for a reason. It gives your messages structure without being annoying about it. The format is simple:

type(scope): description

feat(auth): add password reset via email
fix(cart): prevent negative quantities on update
docs(readme): add local development setup steps
refactor(api): extract validation into middleware

The widely accepted best practice says keep your subject line under 50 characters, use imperative mood („add feature“ not „added feature“), and if you need more detail, leave a blank line and write a body wrapped at 72 characters. Most people skip the body, and that’s honestly fine for 90% of commits.

But the imperative mood thing? That matters more than you think. Read your commit message as „If applied, this commit will [your message].“ So „add password reset“ reads as „If applied, this commit will add password reset.“ Makes sense. „Added password reset“ reads as „If applied, this commit will added password reset.“ Nope.

Small thing. Makes a huge difference when you’re reading a git log six months later trying to figure out where everything went sideways.

The .gitignore File You Should Have Created Yesterday

If your repo doesn’t have a .gitignore, stop reading and go create one right now. I’ll wait.

This is probably the single most common beginner mistake I see. People push node_modules/ (300MB of dependencies), .env files with API keys, .DS_Store files, IDE configuration folders — all of it going straight into the repository for everyone to download forever. And here’s the fun part: even after you add a .gitignore, files that were already tracked stay tracked. You have to explicitly remove them with git rm --cached.

If you’re working with Python virtual environments, your venv/ folder is a classic offender. Same deal with __pycache__/. GitHub maintains a collection of .gitignore templates at github.com/github/gitignore — use them. There’s one for basically every language and framework.

Minimum viable .gitignore for a web project:

node_modules/
.env
.env.local
dist/
.DS_Store
*.log
.vscode/
.idea/

What Happens When You Mess Up (and You Will)

Git has an undo for almost everything. The trick is knowing which undo to use.

Quick reference for the three situations you’ll actually encounter:

You committed something you shouldn’t have: git reset --soft HEAD~1 undoes the last commit but keeps your changes staged. Safe. Friendly. Use this one a lot.

You need to completely undo your last commit and all its changes: git reset --hard HEAD~1. This is the scary one. Those changes are gone. Well, not technically — git reflog can save you within about 30 days — but treat it as gone.

You pushed something bad to a shared branch: git revert HEAD. This creates a NEW commit that undoes the previous one. This is the polite way to undo things on shared branches because it doesn’t rewrite history.

Which brings me to the single most important rule of Git that I learned the hardest possible way.

Never, Ever Force Push to a Shared Branch

Never.

I force-pushed to main once in 2019. On a team project. On a Friday afternoon, because of course it was a Friday. I had rebased locally, thought I was being clever cleaning up history, and git push --force‚d to main. Three other developers had pulled and branched off commits that no longer existed. We spent the better part of Monday untangling the mess. One colleague lost about a week of uncommitted work because they’d been working off a now-orphaned branch and didn’t realize until they tried to merge.

I felt sick about it for days. And I never force-pushed to a shared branch again.

If you absolutely must force push (say, after a rebase on your own feature branch that nobody else is using), use git push --force-with-lease. It checks if anyone else has pushed to that branch since you last pulled, and refuses to overwrite their work. It’s a seatbelt. Wear it.

Staging: The Feature Most Beginners Ignore

The staging area is Git’s best feature and most beginners skip straight past it. They git add . everything and commit. Which means every commit is a grab bag of unrelated changes — a CSS fix, a new feature, and some debug console.log statements nobody wanted, all mushed into one commit.

The staging area lets you craft commits. Changed five files but only three are related to the feature you’re working on? Stage those three. Commit. Then stage the other two separately.

git add src/components/Header.jsx
git add src/styles/header.css
git commit -m "feat(header): add responsive navigation menu"

git add src/utils/debug.js
git commit -m "chore: add debug utility for API responses"

This approach works beautifully with the kind of modular thinking you need for layout decisions like choosing between CSS Grid and Flexbox — break the problem down, handle each piece deliberately.

Even better: git add -p lets you stage individual chunks within a file. Changed a function at the top AND fixed a typo at the bottom? You can stage them separately. It’s interactive and a bit fiddly at first, but once you get used to it, you’ll wonder how you lived without it.

My Actual Daily Workflow

I’m going to be real with you — I don’t follow some elaborate ritual. Here’s genuinely what I do every day:

Morning: git pull on main. Create a branch for whatever I’m working on. Name it descriptively — fix/broken-login-redirect beats fix/stuff every time.

During the day: small, frequent commits. I aim for commits that do one thing. Sometimes I fail at this and commit something messy — ngl, it happens. But the goal is there.

Before pushing: git log --oneline -10 to review what I’ve done. Sometimes I’ll git rebase -i to squash a couple of „WIP“ commits into something presentable. This is the one time rewriting history is totally fine — it’s your branch, nobody else has it.

Push, open PR, get it merged, delete the branch locally and remotely. Start over.

That’s it. No magic. Just consistency.

FAQ

What’s the difference between git merge and git rebase?

Merge creates a new „merge commit“ that joins two branches together, preserving all history. Rebase replays your commits on top of another branch, making a linear history. For beginners, stick with merge — it’s safer and harder to mess up. Explore rebase once you’re comfortable with branching.

How often should I commit?

Commit whenever you complete a logical unit of work. Finished a function? Commit. Fixed a bug? Commit. Added a test? Commit. Multiple small commits are always better than one giant commit at the end of the day. Think of commits like save points in a video game.

Should I commit directly to main?

On a solo project with no CI/CD pipeline, honestly, it’s fine for tiny changes. But building the habit of using feature branches now saves you pain later. On any team project, never commit directly to main — always use branches and pull requests.

What’s a pull request actually for?

A pull request (PR) is a request to merge your branch into another branch — usually main. It gives others a chance to review your code, leave comments, and suggest changes before the code enters the main codebase. Even on solo projects, PRs create a useful record of what changed and why.

How do I undo a git add?

Use git restore --staged filename (Git 2.23+) or git reset HEAD filename (older versions). This unstages the file without losing your changes. The file stays modified in your working directory — it just won’t be included in your next commit.

What is a detached HEAD and should I panic?

No panic needed. A detached HEAD means you checked out a specific commit instead of a branch. Any commits you make won’t belong to any branch. To fix it, either create a branch from where you are (git checkout -b new-branch) or switch back to an existing branch (git checkout main).

Is GitHub the same as Git?

No. Git is the version control software that runs locally on your machine. GitHub is a cloud platform that hosts Git repositories and adds collaboration features like pull requests, issues, and actions. Alternatives to GitHub include GitLab and Bitbucket, but they all use Git underneath. With 85% market share, Git itself is basically universal at this point.

How do I write a good .gitignore from scratch?

Start with a template from github.com/github/gitignore that matches your language or framework. Then add project-specific files: environment files (.env), build output (dist/, build/), editor configs (.vscode/, .idea/), and OS files (.DS_Store, Thumbs.db). The rule of thumb: if it’s generated, personal, or secret, it doesn’t belong in Git.


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert