15 minworkshop

Feature Branch Workflow

Feature Branch Workflow

Practice the complete lifecycle of a feature branch: create, develop, push, PR, merge, and cleanup.

Setup

Use an existing GitHub-connected repository or create one:

bash
1$ mkdir branch-practice && cd branch-practice
2$ git init
3$ echo "# Branch Practice" > README.md
4$ git add README.md
5$ git commit -m "docs: initial README"
6
7# Connect to GitHub (use your own repo)
8$ gh repo create your-username/branch-practice --private --source=. --remote=origin --push

Exercise 1: Create a Feature Branch

Update Main First

bash
1$ git switch main
2$ git pull --ff-only
3Already up to date.

Create the Branch

bash
1$ git checkout -b feature/add-greeting
2Switched to a new branch 'feature/add-greeting'

Verify

bash
1$ git branch
2 main
3* feature/add-greeting

Exercise 2: Develop the Feature

Create a File

bash
1$ cat <<'EOF' > greeting.js
2function greet(name) {
3 const hour = new Date().getHours();
4
5 if (hour < 12) {
6 return `Good morning, ${name}!`;
7 } else if (hour < 18) {
8 return `Good afternoon, ${name}!`;
9 } else {
10 return `Good evening, ${name}!`;
11 }
12}
13
14module.exports = { greet };
15EOF

First Commit

bash
1$ git add greeting.js
2$ git commit -m "feat: add time-aware greeting function"
3[feature/add-greeting 2a3b4c5] feat: add time-aware greeting function
4 1 file changed, 14 insertions(+)
5 create mode 100644 greeting.js

Add More to the Feature

bash
1$ cat <<'EOF' > index.js
2const { greet } = require('./greeting');
3
4const name = process.argv[2] || 'World';
5console.log(greet(name));
6EOF
7
8$ git add index.js
9$ git commit -m "feat: add CLI entry point"
10[feature/add-greeting 3b4c5d6] feat: add CLI entry point
11 1 file changed, 4 insertions(+)
12 create mode 100644 index.js

View Branch History

bash
1$ git log --oneline
23b4c5d6 (HEAD -> feature/add-greeting) feat: add CLI entry point
32a3b4c5 feat: add time-aware greeting function
41a2b3c4 (origin/main, main) docs: initial README

Exercise 3: Push and Create PR

Push Branch to Remote

bash
1$ git push -u origin feature/add-greeting
2Enumerating objects: 7, done.
3...
4To github.com:your-username/branch-practice.git
5 * [new branch] feature/add-greeting -> feature/add-greeting
6Branch 'feature/add-greeting' set up to track remote branch 'feature/add-greeting' from 'origin'.

Create Pull Request

Option A: Using gh CLI

bash
1$ gh pr create --fill
2Creating pull request for feature/add-greeting into main in your-username/branch-practice
3
4https://github.com/your-username/branch-practice/pull/1

Option B: Custom title and body

bash
1$ gh pr create --title "Add time-aware greeting" --body "This PR adds a greeting function that says good morning/afternoon/evening based on the current time.
2
3## Changes
4- greeting.js: Time-aware greeting function
5- index.js: CLI entry point
6
7## Testing
8\`\`\`bash
9node index.js Alice
10\`\`\`"

View PR

bash
1$ gh pr view
2Add time-aware greeting #1
3Open • your-username wants to merge 2 commits into main from feature/add-greeting
4...

Exercise 4: Merge the PR

Using Squash Merge

bash
1$ gh pr merge --squash --delete-branch
2✔ Squashed and merged pull request #1 (Add time-aware greeting)
3✔ Deleted branch feature/add-greeting and switched to branch main

This:

  • Squashes all commits into one
  • Merges to main
  • Deletes the remote branch
  • Switches you to main

Verify Merge

bash
1$ git pull
2$ git log --oneline
34c5d6e7 (HEAD -> main, origin/main) Add time-aware greeting (#1)
41a2b3c4 docs: initial README

Notice: Two commits became one squashed commit.

Exercise 5: Clean Up Local Branch

The remote branch was deleted, but check local:

bash
1$ git branch
2* main

If the branch still existed locally:

bash
1$ git branch -d feature/add-greeting
2Deleted branch feature/add-greeting (was 3b4c5d6).

Prune Stale Remote References

bash
1$ git fetch --prune

This removes local references to deleted remote branches.

Exercise 6: Second Feature (Practice)

Repeat the workflow with another feature:

bash
1# 1. Create branch
2$ git checkout -b feature/add-farewell
3
4# 2. Add code
5$ cat <<'EOF' >> greeting.js
6
7function farewell(name) {
8 return `Goodbye, ${name}! See you next time.`;
9}
10
11module.exports = { greet, farewell };
12EOF
13
14# 3. Commit
15$ git add greeting.js
16$ git commit -m "feat: add farewell function"
17
18# 4. Push
19$ git push -u origin feature/add-farewell
20
21# 5. Create PR
22$ gh pr create --fill
23
24# 6. Merge
25$ gh pr merge --squash --delete-branch
26
27# 7. Verify
28$ git pull
29$ git log --oneline

Final Verification

Your history should show clean, squashed merges:

bash
1$ git log --oneline --graph
2* 5d6e7f8 (HEAD -> main, origin/main) Add farewell function (#2)
3* 4c5d6e7 Add time-aware greeting (#1)
4* 1a2b3c4 docs: initial README

Checklist

  • Created feature branch from main
  • Made multiple commits on the branch
  • Pushed branch to remote with -u
  • Created PR using gh pr create
  • Merged PR with --squash --delete-branch
  • Local main is up to date after merge
  • Completed second feature for practice

Cleanup

If you want to delete the practice repository:

bash
1$ gh repo delete your-username/branch-practice --yes
2$ cd ..
3$ rm -rf branch-practice

Key Takeaway

The feature branch workflow—branch, commit, push, PR, merge, delete—is the foundation of collaborative development. Practice it until it's automatic.