From Chaos to Clarity: My GitHub Workflow Journey
How I Learned to Stop Treating GitHub Like Cloud Storage and Start Using Branches the Right Way
For years I treated GitHub like simple cloud storage, pushing everything straight to the main branch. That was the biggest mistake of my coding journey. Only recently did I take the time to understand how GitHub is meant to be used and why I should have adopted it properly from the start.
I’ve always had a (bad) habit of diving into projects however I wanted, with little planning or documentation beyond what lived in my head. While that freedom had its advantages, it left me constantly juggling too many moving parts at once. What I really needed was structure: a clear plan, documentation, and an organized workflow that let me focus on one piece at a time and integrate it cleanly into the larger project.
The lesson was simple: the main branch should be reserved for stable, tested code. Active development belongs in feature branches, each dedicated to a specific part of the project. To keep main even cleaner, a dev branch acts as the integration point where the feature branches merge into dev for testing, and only fully verified versions move from dev into main.
How to Keep the Whole Project In-Sync
One of the biggest lessons I learned was that there is still more steps required after merging a feature branch into the dev branch. Once the dev branch picks up the new changes, every other feature branch still needs to be updated as well. Otherwise, they fall behind and create conflicts later.
My workflow now looks like this: I commit changes on a feature branch and push them to GitHub. Then I merge that branch into dev and run tests to make sure everything works together. Once dev is stable, I merge it back into the other feature branches so they all stay aligned. Finally, I push those updates to GitHub.
This simple discipline keeps every branch current, prevents surprises, and makes the eventual merge into main smooth and conflict‑free.
A simple sync.bat file, like below, can be used to automate this process as it can be very repetitive.
@echo off
REM sync.bat used to merge dev into all feature branches
setlocal
REM List of branches to sync
set branches=feature/ui-menus feature/tests feature/lobby-session
for %%b in (%branches%) do (
echo.
echo ===== Syncing %%b =====
git checkout %%b
git merge dev
git push origin %%b
)
REM Return to dev branch at the end
git checkout dev
endlocal
echo.
echo All branches synced with dev!
pause
Working Example
Let’s walk through an example situation. Assume this repo has a ‘main’ branch that holds 100% tested versions that come only from merging from the ‘dev’ branch. While the ‘dev’ branch has not quite 100% tested versions that come only from merging from the ‘feature/’ branches.
First, switch to the correct feature branch with:
git checkout feature/ui-menus
Or create the feature branch if it doesn’t exist:
git checkout -b feature/ui-menus
Now, stage (just means you plan on committing) all changes with a period or you can specify a single file:
git add sync.bat
Or stage all:
git add .
Next, you commit those staged changes with a clear and concise message:
git commit -m “chore: add sync.bat script for branch syncing”
Then push the changes to GitHub:
git push origin feature/ui-menus
Merge the feature branch into the ‘dev’ branch by first switching to the ‘dev’ branch:
git checkout dev
Then merging:
git merge feature/ui-menus
And pushing to GitHub:
git push origin dev
At this point you’re most likely ready to submit a proper pull request or if you’re working solo you could edit and utilize the sync.bat file to sync the rest of your branches with the new dev branch or by manually merging the dev branch into each feature branch.
Finally, if the app is stable and tested then it is ready to be merged into the main branch. First switch to the main branch:
git checkout main
Then merge with dev:
git merge dev
And push to GitHub:
git push origin main
Glossary
Below is a list of the most common commands that will turn you into a GitHub pro in no time.
git status
Show remote URL (verify working on correct repo):
git remote -v
========Files (BE CAREFUL!)========
Discard local changes (dangerous but useful to restore from commit):
git restore <file>
Or
git reset --hard
Clean up untracked files (preview files to be removed):
git clean -fdn
Then to remove them:
git clean -fd
========Branches========
List current branch:
git branch
Current branch name only:
git rev-parse --abbrev-ref HEAD
List all branches:
git branch -a
List remote branches:
git fetch origin
git branch -r
Switch to a branch:
git checkout branch-name
Or if it only exists remotely:
git checkout -b branch-name origin/branch-name
Pull latest changes from remote:
git pull origin branch-name
Show differences between branches:
git diff branchA..branchB
Create a new branch (will switch to it):
git checkout -b new-branch-name
Push it to GitHub:
git push origin new-branch-name
Rename a branch (local):
git branch -m old-name new-name
Then push to GitHub:
git push origin -u new-name
git push origin --delete old-name
Delete a branch (local):
git branch -d branch-name
(remote):
git push origin --delete branch-name
Merge 1 branch into another:
git checkout target-branch
git merge source-branch
(eg. git merge feature/ui-menus)
Push to GitHub:
git push origin target-branch
Revert a merge:
Find the merge commit hash:
git log --oneline
Then:
git revert -m 1 <merge-commit-hash>
(-m 1 tells Git which parent branch to keep (usually the branch you merged into).)
=======Commits======
Make a commit:
git add .
git commit -m “feat: describe the change here”
See all commits in current branch:
git log --oneline --graph --decorate
Undo / revert to a specific commit:
Soft reset (keep changes staged):
git reset --soft <commit-hash>
Hard reset (discard changes):
git reset --hard <commit-hash>
Revert (make a new commit that undoes):
git revert <commit-hash>
Stash changes (save temporarily eg. so you can switch branches):
git stash
Then apply those changes in current branch:
git stash pop
See stashes list (if you stash multiple times):
git stash list
Apply a specific stash:
git stash apply stash@{2}
See differences before committing:
unstaged changes:
git diff
staged changes:
git diff --staged
Undo last commit but keep changes:
git reset --soft HEAD~1
Show commit history with file changes:
git log --stat
Tag a commit (e.g. for releases):
git tag v1.0.0 <commit-hash>
Then Push to GitHub:
git push origin v1.0.0


