Developers dive into CI/CD setups dreaming of Git Flow’s elegance — develop, feature, release branches humming in sync. That’s the script, right? Enterprise templates scream it, tutorials drill it. But here’s the twist: in a fresh VM, tight deadline, or solo sprint, that complexity craters your pipeline before takeoff.
This single-branch manifesto upends it. One branch. Main. Push iteratively. Pipelines fire predictably. No branch roulette.
“If your goal is to get a working CI/CD pipeline running quickly and reliably, the safest approach is often the simplest one.”
Spot on. Pulls from real trenches, where Git Flow’s promise — structured releases, isolated features — morphs into nightmare fuel: wrong-branch pushes, silent pipelines, endless YAML tweaks.
Why Expect Git Flow — And Why It Backfires
Git Flow hit in 2010, Vincent Driessen’s gift to scaling teams. Feature branches sprout, hotfixes dart in, main stays sacred. Logical for 20 devs churning releases. But for your isolated project? Overkill.
You’re unzipping code on a VM. Pip install. Pytest green. App spins on localhost. Excitement builds — now CI/CD magic. Git Flow says: checkout develop, branch feature/docker, PR to main. Wait.
Pipeline ghosts you. Why? .gitlab-ci.yml wired for ‘main’ only. Develop pushes? Crickets. Or worse, jobs misfire on untested branches.
It shifts architecture underfoot. CI/CD thrives on determinism — every push, same trigger, same path. Branches multiply variables. Debug Git, not deploy.
Look, I chased Git Flow early career. Shipped delays, rage-commits. Then Linux kernel vibe hit me: linear history, no merges till stable. Simplicity scales. That’s my angle here — not in original, but echoes how Torvalds ditched branches for mainline purity. CI/CD craves that.
Short para punch: Ditch the branches.
The One-Branch Ritual: Step-by-Push Precision
Init clean.
mkdir -p ~/work && cd ~/work
Unzip, verify: pip install -r requirements.txt; pytest; python3 app.py; curl localhost:5000.
Git it: git init; git branch -M main; git remote add origin http://gitlab.localdomain/your-username/project.git; git add .; git commit -m “Initial project import”; git push -u origin main.
Boom. Baseline in GitLab. Pipeline? Not yet — that’s deliberate.
Next: hygiene. .gitignore blocks venv/, pycache/, .env, .sonar/. Commit: “Add gitignore and cleanup”. Push.
Docker time — if needed. Dockerfile, maybe docker-compose.yml. Commit: “Add Docker setup”. Push. Local run proves it; pipeline will echo.
SonarQube config? sonar-project.properties. No tokens — ever. Push.
Climax: .gitlab-ci.yml. Stages for test, build, scan, deploy. Commit: “Add CI/CD pipeline”. Push.
Fails? Tweak, commit “Fix pipeline issue”, push. Iterate. Each triggers full run. Visibility soars.
This sequence — import, clean, docker, sonar, ci-yml, fix — builds progressively. No big-bang commit hiding sins.
Is a Single Main Branch Enough for Real Teams?
Solo? Ironclad. Teams? Tempting to bolt on develop.
git checkout -b develop; push -u origin develop.
Work there, merge main: git checkout main; git merge develop; push.
But pipeline tweak: only: - main - develop. Deploy jobs? Pin to main only.
Example deploy_dev stage:
script: - docker stop/rm python-app-dev || true - docker run -d –network host –name python-app-dev python-app:latest only: - main
Keeps prod safe. Develop tests code; main deploys.
Yet — and here’s the skepticism — even this invites drift. Main lags. Merge conflicts brew. Back to square one: complexity creep.
Original skips a beat: in constrained envs (VM, hackathon), one branch demos full flow sans risk. Proves CI/CD works before scaling.
Architectural why: Pipelines as linear factories. Branches? Forked assembly lines colliding.
But wait — corporate GitLab docs nudge Git Flow. Hype? Sure, sells enterprise tiers. Reality: most pipelines die on Git friction, not YAML depth.
Why Does This Matter for Developers Right Now?
CI/CD fatigue real. Tools promise automation; Git snarls it. This flips to momentum: push, watch, fix, repeat.
Fewer failure points. No “pushed to feature, where’s my job?” No tokens leaked via dumb commits. Predictable triggers mean faster feedback.
Bold call: In 2024’s agentic dev world — AI suggesting code, pipelines validating — simplicity wins races. Complex flows bog LLMs too; they hallucinate branches.
Historical nod again: Early Docker adoption? Single branches got containers to prod first. Not Git Flow ceremonies.
Wander a sec: Imagine VM spins down mid-setup. With one branch, you’re resuming from last push. Branches? Rebase hell.
Push order mantra: project → gitignore → docker → sonar → ci-yml → fixes. Logical layers, each testable.
Common Traps This Dodges — And Proof
Pushed everything at once? Debug monolith.
Tokens in repo? Security breach, pipeline halts.
Git Flow premature? Branch hell, no pipelines.
One branch? All visible, all triggered, all debuggable.
GitLab UI shines: each push a pipeline artifact. Progression clear.
Skeptic lens: Git Flow shines post-pipeline. Prove automation first. Then branch.
🧬 Related Insights
- Read more: Scraping DoorDash Menus in 2026: Code That Dodges the Bots
- Read more: Homelabs 2026: AI-Fueled Software Renaissance Amid Hardware Drought
Frequently Asked Questions
What’s the simplest Git workflow for CI/CD pipelines?
One branch: main. Push iteratively — project, gitignore, dockerfile, .gitlab-ci.yml. Triggers reliably, no branch confusion.
Git Flow vs single branch: which for beginners?
Single branch crushes for first pipelines. Git Flow adds risk; use after basics work.
Does GitLab CI run on non-main branches?
Only if configured (only: - main - develop). For deploys, restrict to main.