Overview
Branch off main, commit on the branch, push it, open a pull request, merge after review, then update main. Nobody commits straight to main.
On this page7 sections
Goal
On your own laptop you can commit straight to your project. On a team, that is a bad idea. If everyone commits straight to the shared main branch, one bad change breaks the project for everybody. Teams use a different routine: make a branch, do your work there, and ask a teammate to review it before it joins main. That routine is called a pull request workflow.
In this lesson you learn the seven commands of that routine. You need the basics from the earlier Git lesson (add and commit) and a free GitHub account to try it for real.
This tab has no Git remote
The exercise stores history as a Python list. The real commands need Git installed and a repository on GitHub. After you pass the exercise, do the routine once on a small test repository of your own.
Why this order
A branch is a separate line of work. Imagine main as the finished, working copy of a document. A branch is a photocopy you can scribble on. Your scribbles do not touch the original. When you are happy with them, you ask someone to look, and only then are they copied back into the original.
The order matters. You make the branch first, so that every commit you make lands on the branch and not on main. You push the branch so that GitHub has a copy for others to see. You open a pull request (PR) so a teammate can read your changes and comment. You merge only after the review. Finally you update your own main so you are ready for the next task.
The full routine. Steps 1 to 4 happen on your laptop. Steps 5 and 6 happen on GitHub.
| Step | Command or action | What it protects |
|---|---|---|
| 1. Start from fresh main | git switch main, then git pull | You build on the latest work, not an old copy |
| 2. Make a branch | git switch -c fix-date-parsing | Your commits stay off main |
| 3. Work and commit | git add file, then git commit -m "message" | Small steps you can review and undo |
| 4. Push the branch | git push -u origin fix-date-parsing | GitHub gets a copy others can see |
| 5. Open a pull request | Click "Compare & pull request" on GitHub | A teammate reviews before anything changes main |
| 6. Merge | Click "Merge pull request" after approval | Only reviewed work joins main |
| 7. Update and clean up | git switch main, git pull, git branch -d fix-date-parsing | Your laptop matches GitHub again |
The checklist
- git switch main && git pull. Make sure you start from the newest main.
- git switch -c fix-date-parsing. Create the branch and move onto it in one step. Pick a name that says what the work is.
- Edit your files. Run git status to see what changed. Run git diff to read the exact changes line by line.
- git add transform.py, then git commit -m "Fix date parsing for Pune orders". Stage only the files that belong to this change.
- git push -u origin fix-date-parsing. Send the branch to GitHub. The -u flag remembers the link, so later you can just type git push.
- Open GitHub. It shows a yellow banner with a button to open a pull request. Write what changed and why in two or three lines.
- Wait for a review. If the reviewer asks for changes, edit, commit and push again. The pull request updates by itself.
- After the merge, run git switch main, git pull, and git branch -d fix-date-parsing.
Write branch names that a teammate can understand without opening them. fix-date-parsing and add-orders-test are good. test2 and asha-new are not. Write commit messages that say what and why. 'Fix date parsing for Pune orders' is better than 'update'.
Worked pass
Here is the routine for a small bug fix. Lines that start with $ are what you type.
$ git switch main $ git pull Already up to date. $ git switch -c fix-date-parsing Switched to a new branch 'fix-date-parsing' $ git status --short M transform.py $ git add transform.py $ git commit -m "Fix date parsing for Pune orders" [fix-date-parsing 8d41b2e] Fix date parsing for Pune orders 1 file changed, 3 insertions(+), 1 deletion(-) $ git push -u origin fix-date-parsing branch 'fix-date-parsing' set up to track 'origin/fix-date-parsing'.
After the push, GitHub prints a link in the terminal. Open it, click to create the pull request, and write a short description. When your teammate approves, you click Merge. Then back in the terminal:
$ git switch main $ git pull Updating 3f2a9c1..e7a05d3 $ git branch -d fix-date-parsing Deleted branch fix-date-parsing.
Never commit secrets
A password, an API key or a .env file that goes into a commit stays in the history forever, even if you delete it in the next commit. Put secret files in a file called .gitignore so Git never sees them. If you did commit a secret by mistake, treat it as leaked: change the password or key right away.
Do not work on main
If git status says "On branch main" before you start editing, stop and make a branch first. If you already committed on main by mistake, ask a teammate before you try to undo it. Fixing history is easy to get wrong.
Undoing changes: git revert versus git reset
When bugs are deployed or unwanted changes are recorded, Git provides two distinct mechanisms to undo commits, each suited for different collaboration contexts:
Comparison of undo strategies in Git version control.
| Command | Mechanism | Working Tree State | Collaboration Safety |
|---|---|---|---|
| git reset --soft HEAD~1 | Moves HEAD back one commit. | Keeps changes staged in index. | Safe for local, private branches only. |
| git reset --mixed HEAD~1 | Moves HEAD back (default). | Unstages changes into working tree. | Safe for local, private branches only. |
| git reset --hard HEAD~1 | Moves HEAD back, discards diff. | Destroys changes in tree and index. | Dangerous! Permanently discards uncommitted work. |
| git revert <commit_hash> | Appends a new inverse commit. | Preserves existing commit history. | Completely safe for shared public branches. |
The fundamental rule of Git undo: NEVER execute git reset on commits that have been pushed to a shared remote branch (such as main). Resetting rewrites history, forcing other developers to manually reconcile divergent commit trees. On shared branches, always use git revert: it creates a new commit that applies the exact reverse diff of the target commit, safely rolling back changes while preserving an unbroken audit log.
Shelving work with git stash
When you are in the middle of modifying a data pipeline and an urgent production bug requires your attention, committing half-finished, broken code is bad practice.
git stash temporarily shelves your uncommitted changes into a local stack, restoring your working tree to a clean state:
- git stash push -m 'wip customer aggregations': Shelves current changes with a descriptive label.
- git stash list: Inspects all shelved stashes in your local repository.
- git stash pop: Re-applies the most recent stashed changes back into your working tree and removes it from the stash stack.
Emergency recovery with git reflog
If you accidentally execute an unwanted git reset --hard or delete a local branch by mistake, Git provides an internal safety net: git reflog (reference log).
While git log only shows commits in the current branch history, git reflog records every single movement of the HEAD pointer on your local machine for the last 30 to 90 days. Typing git reflog reveals every commit hash you have visited.
To recover dropped work, find the commit hash before the accidental reset in the reflog output and restore it: git checkout -b recovery_branch HEAD@{2}. Reflog ensures that in Git, almost no committed data is ever truly lost.
Common beginner questions
What if two people change the same lines?
Git cannot decide which version to keep, so it asks you. That is a merge conflict. The earlier lesson on merge conflicts shows how to fix one. A good habit that avoids many conflicts: keep branches small and short, and run git pull on main often.
Is a pull request a Git feature?
No. It is a feature of GitHub, GitLab and similar sites. Git itself only has branches and merges. The pull request is the place on the website where people talk about a branch and approve it.
Why not commit to main when I am working alone?
For a personal project you can. But branches cost nothing, and practising them alone makes the team routine feel normal. Many data teams also run automatic checks on every pull request, so a branch is how your work gets tested.
What comes next
Next you will meet merge conflicts and fix one by hand. Later, in the CI/CD lessons, you will see how a pull request can start automatic tests, so a broken change is caught before it reaches main.
Practice
The exercise gives you a team's history as a list of (branch, message) pairs. The team rule is that nobody commits straight to main. Write direct_commits() to find the commits that broke the rule.
Practicals · load into the editor
After you read the theory, run these in the pane on the right. They execute in this tab, no cluster.