Beginner → Team-Ready
0%
Lesson 1Foundations

What is Git?

Git is a version control system — it tracks every change you make to your code, lets you travel back in time, and lets multiple people work on the same project without overwriting each other. It's the single most important tool in a developer's workflow.

Imagine writing a 500-line Java program over two weeks. On day 14 you introduce a bug. Without Git, you have no way to know what changed or when. With Git, you can see exactly which line you changed on which day, compare old and new versions, and restore any previous state in seconds.

Git was created in 2005 by Linus Torvalds — the same person who created Linux — specifically to manage the Linux kernel codebase, which thousands of developers contribute to simultaneously. Today it's used by virtually every software team on the planet.

Git vs. GitHub — not the same thing

This is the most common beginner confusion:

GitGitHub
gitgithub.com
Software on your computerA website that hosts Git repos online
Tracks changes locallyShares your code with the world/team
Works completely offlineRequires an internet connection
Free, open-sourceFree tier + paid plans

Think of Git as the engine and GitHub as the garage where you park and share your car. You could use Git without GitHub — but GitHub is where collaboration happens.

Why every developer uses Git

  • Safety net — you can always undo any mistake
  • History — every change is logged with who, what, and when
  • Collaboration — multiple developers edit the same code without conflicts
  • Branching — work on new features without touching working code
  • Deployment — many hosting services deploy directly from a Git repo
💡
employers expect this

Every professional developer job listing mentions Git. Not knowing it is a dealbreaker for team roles. By the end of this course, Git will feel as natural as saving a file.

Quick Check
A colleague says "push your changes to GitHub." What does that mean?
Lesson 2Foundations

Installation & Setup

Install Git on your machine and tell it who you are. Every commit you make will be signed with your name and email — this is how teams know who changed what.

Install Git

1

macOS

Install Homebrew first (brew.sh), then run: brew install git. Alternatively, install Xcode Command Line Tools: xcode-select --install

2

Windows

Download Git for Windows from git-scm.com. During install, select "Git from the command line and also from 3rd-party software". This also installs Git Bash — a terminal that works like Linux.

3

Linux (Ubuntu/Debian)

sudo apt-get update && sudo apt-get install git

4

Verify the install

Open your terminal and run git --version. You should see something like git version 2.42.0.

Configure your identity

Before your first commit, tell Git who you are. This information is embedded in every commit you create:

Terminal
# Set your name and email — use the same email as your GitHub account
$ git config --global user.name "Alex Johnson"
$ git config --global user.email "alex@example.com"

# Set VS Code (or any editor) as Git's default editor
$ git config --global core.editor "code --wait"

# Make 'main' the default branch name (modern standard)
$ git config --global init.defaultBranch main

# Verify your settings
$ git config --list
user.name=Alex Johnson
user.email=alex@example.com
core.editor=code --wait
init.defaultBranch=main
⚠️
--global applies everywhere

The --global flag saves these settings for all repos on your machine. If you work on a specific project that needs different credentials (e.g. a work vs. personal project), run the same commands inside that folder without --global.

Create a GitHub account

Go to github.com and sign up with the same email you used above. Choose a professional username — you'll be putting this on your resume.

Quick Check
Why does Git need your name and email before you start committing?
Lesson 3Foundations

Your First Repo

A repository (repo) is a folder that Git is tracking. You create one with a single command — and from that moment, Git watches every change inside it. Let's make your first one.

Terminal — creating a repo from scratch
# Create a new folder and navigate into it
$ mkdir my-java-project
$ cd my-java-project

# Initialize Git — this creates a hidden .git folder
$ git init
Initialized empty Git repository in /Users/alex/my-java-project/.git/

# Check the current state of your repo
$ git status
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)

What just happened?

Running git init created a hidden folder called .git inside your project. This is Git's database — it stores your entire history, configuration, and everything Git needs. You should never edit files inside .git manually.

Anatomy of git status

git status is your most-used command. It tells you exactly where you stand: which files have changed, which are staged, and what's ready to commit. Get into the habit of running it constantly.

Terminal — adding files and checking status
# Create a file
$ echo "public class Main {}" > Main.java

# Check status again — Git sees the new file
$ git status
On branch main
No commits yet

Untracked files:
  (use "git add <file>" to include in what will be committed)
        Main.java

nothing added to commit but untracked files present
💡
untracked vs. tracked

New files are "untracked" — Git sees them but isn't recording their changes yet. You have to explicitly tell Git to start tracking a file with git add. This two-step design (add, then commit) gives you precise control over what goes into each commit.

Your Turn

Initialize your Task Manager repo

Take the Task Manager project from the Java beginner course:

  • Navigate to the project folder in your terminal
  • Run git init
  • Run git status and read every line of the output
  • What files does Git see? Are they tracked or untracked?
Quick Check
What does git init actually do to your folder?
Lesson 4Foundations

Staging & Committing

A commit is a saved snapshot of your project. Before committing, you stage changes — choosing exactly what goes into that snapshot. This two-step system is Git's most important concept.

The three areas of Git

Every file in a Git project lives in one of three places:

AreaWhat it isHow to move here
Working directoryYour actual files on disk — where you edit(files start here)
Staging area (index)A draft of your next commit — curated changesgit add <file>
Repository (.git)Permanent history — committed snapshotsgit commit
Terminal — the full add/commit workflow
# See what changed
$ git status
Untracked files: Main.java, Task.java

# Stage a specific file
$ git add Main.java

# Stage all changes in the current folder
$ git add .

# See what's staged (green = staged, red = unstaged)
$ git status
Changes to be committed:
        new file:   Main.java
        new file:   Task.java

# Commit with a message describing WHAT and WHY
$ git commit -m "Add initial Task Manager files"
[main (root-commit) a3f2c91] Add initial Task Manager files
 2 files changed, 47 insertions(+)
 create mode 100644 Main.java
 create mode 100644 Task.java

# Unstage a file before committing (doesn't delete the change)
$ git restore --staged Task.java

# See WHAT changed in a file (diff of working dir vs staged)
$ git diff
# See diff of staged vs last commit
$ git diff --staged

Writing good commit messages

A commit message is a note to your future self and your teammates. Bad messages like "fix stuff" or "wip" are useless in a log. Good messages follow this pattern:

Good vs. bad commit messages
❌  git commit -m "fix"
❌  git commit -m "changes"
❌  git commit -m "asdfgh"
❌  git commit -m "WIP dont push"

✓  git commit -m "Add input validation to TaskManager.addTask()"
✓  git commit -m "Fix NPE when task file doesn't exist on first run"
✓  git commit -m "Rename completeTask() to markComplete() for clarity"
✓  git commit -m "Remove debug print statements before release"
⚠️
commit often, commit small

The biggest beginner mistake is coding for 4 hours then doing one massive commit. Commit every time you complete a small, logical unit of work. Small commits are easier to understand, easier to revert, and tell a clear story in the log.

Your Turn

Make your first 3 commits

In your Task Manager project:

  • Stage and commit the Task.java file alone with message "Add Task model class"
  • Stage and commit TaskManager.java with message "Add TaskManager with file persistence"
  • Add a README.md file with a title and short description, then commit it
  • Run git log to see your three commits
Quick Check
You've edited 3 files but only want to commit 1 of them right now. What do you do?
Lesson 5Foundations

Viewing History

Git keeps every version of your project forever. Knowing how to read the history — and navigate it — turns Git from a backup tool into a time machine.

Terminal — exploring your commit history
# Full log — each commit on multiple lines
$ git log
commit a3f2c91b7e4d8f3a2c1b9e7f5d4a3b2c1d9e7f5
Author: Alex Johnson <alex@example.com>
Date:   Mon Jan 15 14:32:00 2024

    Add input validation to TaskManager.addTask()

commit b2e1d9f8c7a6b5e4d3c2b1a9f8e7d6c5b4a3f2
Author: Alex Johnson <alex@example.com>
Date:   Mon Jan 15 11:15:00 2024

    Add TaskManager with file persistence

# Compact one-line log
$ git log --oneline
a3f2c91 Add input validation to TaskManager.addTask()
b2e1d9f Add TaskManager with file persistence
c1d9e7f Add Task model class
d4a3b2c Initial commit — add README

# Visual branch graph (very useful with branches!)
$ git log --oneline --graph --all
* a3f2c91 Add input validation
* b2e1d9f Add TaskManager
* c1d9e7f Add Task model
* d4a3b2c Initial commit

# See exactly what changed in a specific commit
$ git show a3f2c91
diff --git a/TaskManager.java b/TaskManager.java
--- a/TaskManager.java
+++ b/TaskManager.java
-    public void addTask(String title) {
-        tasks.add(new Task(title, "MEDIUM"));
+    public void addTask(String title, String priority) {
+        if (title.isBlank()) { System.out.println("Empty title."); return; }
+        tasks.add(new Task(title.trim(), priority));

# See who changed which line in a file (blame!)
$ git blame TaskManager.java
a3f2c91 (Alex  Jan 15) public void addTask(String title, String priority) {
b2e1d9f (Alex  Jan 15) private ArrayList<Task> tasks = new ArrayList<>();
💡
commit hashes

That long hex string like a3f2c91b7e4d... is a unique ID for every commit — called a SHA hash. You never need to type the full thing; the first 7 characters are enough for Git to identify it. In commands like git show or git revert you just use the short form.

Quick Check
You want to see a compact one-line summary of your last 10 commits. Which command is best?
Lesson 6Branching

Branches

Branches are Git's killer feature. A branch is an independent line of development — you can work on a new feature in complete isolation, and your working code on main is never touched until you're ready.

Think of branches like parallel universes. On main, your task manager works perfectly. You create a branch called feature/due-dates and start adding due date functionality. If it breaks things, no problem — main is completely unaffected. When it's ready, you merge it back.

Terminal — working with branches
# See all branches (* marks your current branch)
$ git branch
* main

# Create a new branch
$ git branch feature/due-dates

# Switch to it
$ git checkout feature/due-dates
Switched to branch 'feature/due-dates'

# Better: create AND switch in one command (modern syntax)
$ git switch -c feature/search
Switched to a new branch 'feature/search'

# Now make changes and commit — only on this branch
$ git add .
$ git commit -m "Add searchTasks() method with case-insensitive matching"
[feature/search 7f3a1b2] Add searchTasks() method

# Switch back to main — your changes are NOT here
$ git switch main
Switched to branch 'main'

# See all branches including remote
$ git branch -a
* main
  feature/due-dates
  feature/search

# Delete a branch (after merging)
$ git branch -d feature/search
Deleted branch feature/search (was 7f3a1b2).
Interactive: branch visualizer
Click the buttons to see how branches work
💡
branch naming conventions

Use slashes to organise branches: feature/add-search, bugfix/null-pointer, hotfix/login-crash, release/v1.2.0. Hyphens, not spaces. All lowercase. This is the standard on professional teams.

Quick Check
You're on main and run git switch -c bugfix/login. Where are you now?
Lesson 7Branching

Merging

Merging brings a branch's changes back into another branch. It's how your feature work eventually lands in main. There are two kinds — and knowing the difference matters.

Fast-forward merge

When main hasn't changed since you branched off, Git can simply move the pointer forward. No new commit is created — it's the cleanest kind of merge.

Terminal — merging a branch
# You're on main. You want to bring in feature/search.
$ git switch main

$ git merge feature/search
Updating b2e1d9f..7f3a1b2
Fast-forward
 TaskManager.java | 12 ++++++++++++
 1 file changed, 12 insertions(+)

# After a clean merge, delete the branch
$ git branch -d feature/search
Deleted branch feature/search.

# A merge commit (when both branches have diverged)
$ git merge feature/due-dates
Merge made by the 'ort' strategy.
 Task.java        |  8 ++++++++
 TaskManager.java |  6 ++++++
 2 files changed, 14 insertions(+)

# See the merge commit in log
$ git log --oneline --graph
*   c9f1a2b Merge branch 'feature/due-dates' into main
|\ 
| * 8e4d3c2 Add overdue task filtering
| * 7a1b9f8 Add dueDate field to Task class
* | 6b2c4d1 Fix file loading on empty repo
|/
*  a3f2c91 Add input validation

Rebase — a cleaner alternative

Rebase replays your branch commits on top of the latest main, creating a perfectly linear history. It's preferred for feature branches before merging.

Terminal — rebase before merging
# On your feature branch, rebase onto latest main
$ git switch feature/stats
$ git rebase main
Successfully rebased and updated refs/heads/feature/stats.

# Now merge — it'll be a clean fast-forward
$ git switch main
$ git merge feature/stats
Fast-forward
⚠️
never rebase shared branches

Only rebase branches that you alone are working on. Rebasing rewrites commit history — if someone else has based work on your branch, rebasing destroys their ability to sync. The rule: never rebase main. Rebase feature branches before merging them in.

Quick Check
What is a fast-forward merge?
Lesson 8Branching

Merge Conflicts

A conflict happens when two branches both changed the same line of code. Git doesn't know which version to keep — it asks you to decide. Conflicts sound scary; they're actually straightforward once you've seen one.

Git marks conflicts directly inside the affected file with special markers. You open the file, pick the correct version (or combine them), remove the markers, and commit.

@@ TaskManager.java — conflict markers @@ public void addTask(String title, String priority) { if (title.isBlank()) return; <<<<<<< HEAD ← your current branch (main) + tasks.add(new Task(title.trim(), priority)); + System.out.println("Task added: " + title); ======= ← separator - Task t = new Task(title.trim(), priority); - tasks.add(t); - saveToFile(); >>>>>>> feature/autosave ← the branch you're merging in }

Resolving the conflict

1

Open the file in your editor

VS Code and IntelliJ both highlight conflict markers and offer "Accept Current / Accept Incoming / Accept Both" buttons — much easier than editing manually.

2

Choose what to keep

Delete the conflict markers (<<<<<<<, =======, >>>>>>>) and write the final version you want. Often you combine both sides.

3

Stage the resolved file

git add TaskManager.java

4

Commit the merge

git commit -m "Merge feature/autosave — keep save call and print"

Terminal — conflict workflow
$ git merge feature/autosave
CONFLICT (content): Merge conflict in TaskManager.java
Automatic merge failed; fix conflicts and then commit the result.

# See which files have conflicts
$ git status
both modified:   TaskManager.java

# ... edit the file, resolve the conflict ...

$ git add TaskManager.java
$ git commit -m "Merge feature/autosave — combine save and print"
[main d3a2b1c] Merge feature/autosave

# Abort a merge if things go wrong (returns to pre-merge state)
$ git merge --abort
conflicts are normal

Every developer encounters conflicts. A team working on the same codebase will hit them regularly. Handling them calmly and correctly is a core professional skill — not a sign that something went wrong.

Quick Check
After resolving a merge conflict in a file, what must you do next?
Lesson 9GitHub

Push & Pull

So far everything has been local. Now we connect your repo to GitHub — the moment your code becomes shareable, collaborative, and backed up in the cloud.

1

Create a repo on GitHub

Go to github.com → click the + button → New repository. Name it task-manager. Leave it empty — don't add a README (you already have one locally).

2

Connect your local repo to GitHub

GitHub will show you the commands. The key one is: git remote add origin https://github.com/yourusername/task-manager.git

3

Push your commits

git push -u origin main — the -u links your local main to the remote main so future pushes are just git push.

Terminal — connecting to GitHub and syncing
# Add GitHub as the "origin" remote
$ git remote add origin https://github.com/alexj/task-manager.git

# First push: -u sets upstream tracking
$ git push -u origin main
Enumerating objects: 9, done.
To https://github.com/alexj/task-manager.git
 * [new branch]      main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.

# After that, just:
$ git push

# Push a feature branch to GitHub
$ git push -u origin feature/due-dates

# Pull = fetch + merge. Gets latest changes from GitHub.
$ git pull
remote: Enumerating objects: 3, done.
Updating a3f2c91..9d1e4b7
Fast-forward
 README.md | 5 +++++

# Clone an existing repo to your machine
$ git clone https://github.com/alexj/task-manager.git
Cloning into 'task-manager'...
done.

# See your remotes
$ git remote -v
origin  https://github.com/alexj/task-manager.git (fetch)
origin  https://github.com/alexj/task-manager.git (push)
⚠️
always pull before you push

If a teammate pushed while you were working, your push will be rejected. Always run git pull first to get their changes, resolve any conflicts, then push. Making this a habit prevents 90% of collaboration headaches.

Quick Check
Your push is rejected with "Updates were rejected because the remote contains work that you do not have locally." What should you do?
Lesson 10GitHub

Pull Requests

A Pull Request (PR) is a GitHub feature for proposing changes. You push a branch, open a PR, and teammates review your code before it merges into main. It's the core of professional team collaboration.

Pull Requests are how code review works on every professional team. Even solo developers use them to keep a clean history and have a chance to review their own work before merging. When you apply for a job, interviewers will look at your GitHub PRs.

The Pull Request workflow

1

Create a branch and make your commits

git switch -c feature/sort-tasks → write code → git add . && git commit -m "..."

2

Push the branch to GitHub

git push -u origin feature/sort-tasks

3

Open a Pull Request on GitHub

GitHub shows a banner "Compare & pull request." Click it. Write a title and description explaining what you changed and why. Assign reviewers if working in a team.

4

Code review

Reviewers leave comments on specific lines. You address feedback by pushing new commits to the same branch — the PR updates automatically.

5

Merge the PR

Once approved, click "Merge pull request" on GitHub. Then clean up: git switch main && git pull && git branch -d feature/sort-tasks

💡
write good PR descriptions

A good PR description explains: what this change does, why it was needed, and how to test it. Include screenshots for UI changes. This becomes searchable history — six months later, someone (including you) will search "why was this changed?" and your PR description is the answer.

Your Turn

Open your first real PR

  • Add any small improvement to your Task Manager (sorting, search, statistics)
  • Create a branch, commit your changes, push to GitHub
  • Open a Pull Request — write a title and at least 2 sentences describing what you built
  • Merge it yourself — then pull the merged changes locally
Quick Check
A reviewer leaves a comment on your PR requesting a change. How do you address it?
Lesson 11GitHub

Forking & Open Source

Forking lets you copy someone else's public repository to your account so you can modify it freely — even without permission from the owner. It's how all open-source contribution works.

1

Fork the repo

On any public GitHub repo, click the Fork button. GitHub creates a copy at github.com/your-username/repo-name. You own this copy.

2

Clone your fork

git clone https://github.com/your-username/repo-name.git

3

Add the original as "upstream"

git remote add upstream https://github.com/original-owner/repo-name.git
This lets you pull in updates from the original repo later.

4

Make your changes on a branch

Never commit directly to main in a fork. Create a branch, make your changes, push to your fork.

5

Open a PR to the original repo

GitHub lets you open a PR from your fork's branch to the original repo's main. The maintainer reviews and merges — or asks for changes.

Terminal — keeping your fork in sync
# Fetch updates from the original repo
$ git fetch upstream
From https://github.com/original/repo
 * [new branch]      main -> upstream/main

# Merge upstream changes into your local main
$ git switch main
$ git merge upstream/main
Fast-forward

# Push the updated main to your fork
$ git push
💡
contributing to open source is resume gold

Your first open-source contribution doesn't have to be fixing a complex bug. Fix a typo in documentation. Improve an error message. Add a missing example to a README. Maintainers appreciate all of it, and every merged PR is a public reference that you can work on real code with other developers.

Quick Check
You've forked a repo and want to get the latest changes the original maintainer merged. What do you do?
Lesson 12Real-World

Git Workflows

A workflow is a team agreement about how to use branches. Different teams use different workflows — knowing the common ones means you can join a new team and be productive from day one.

GitHub Flow — simple, widely used

Used by most small-to-medium teams and open-source projects. The rule: main is always deployable. All work happens on feature branches.

GitHub Flow in practice
main  ──●──────────────────────────────────●──
          \                            /
feature   ──●──●──●  (PR review)  merge

# 1. Branch off main
$ git switch -c feature/sort-tasks

# 2. Work and commit
$ git commit -m "Add sort by priority"
$ git commit -m "Add sort by due date"

# 3. Push and open PR
$ git push -u origin feature/sort-tasks

# 4. PR reviewed, approved, merged → delete branch
$ git switch main && git pull && git branch -d feature/sort-tasks

Git Flow — for versioned releases

Used by larger teams shipping versioned software. More complex but gives structure for hotfixes and releases.

BranchPurposeMerges into
mainProduction releases only — tagged v1.0, v1.1...
developIntegration branch — all features merge heremain (at release)
feature/xIndividual featuresdevelop
release/x.yFinal stabilisation before releasemain + develop
hotfix/xUrgent production fixmain + develop
💡
start with GitHub Flow

As a junior developer joining a team, you'll be told which workflow to use. For your own projects, GitHub Flow is almost always the right choice — it's simple, and simple means fewer mistakes.

Quick Check
In GitHub Flow, what is the golden rule about the main branch?
Lesson 13Real-World

Undoing Mistakes

Git's best feature is being able to undo anything. Committed a bug? Deleted the wrong file? Pushed to the wrong branch? There's a Git command for each scenario — and none of them require panic.

Terminal — every undo scenario
── BEFORE STAGING ─────────────────────────────
# Discard changes to a file (back to last commit)
$ git restore Main.java

# Discard ALL unstaged changes
$ git restore .

── AFTER STAGING ──────────────────────────────
# Unstage a file (keeps your edits)
$ git restore --staged Main.java

── AFTER COMMITTING (local only) ──────────────
# Undo last commit — keep changes staged
$ git reset --soft HEAD~1

# Undo last commit — keep changes unstaged
$ git reset HEAD~1

# Fix a typo in the last commit message (before push)
$ git commit --amend -m "Correct message here"

# Add a forgotten file to the last commit
$ git add ForgottenFile.java
$ git commit --amend --no-edit

── AFTER PUSHING (safest undo) ────────────────
# Revert creates a NEW commit that undoes a bad one
# (safe because it doesn't rewrite history)
$ git revert a3f2c91
[main 8b1d4e2] Revert "Add broken feature"

# Temporarily stash work-in-progress
$ git stash
Saved working directory and index state WIP on main
# ... do something else ... then restore:
$ git stash pop

# Last resort: restore a specific file from a commit
$ git checkout a3f2c91 -- Task.java
🚫
never force-push to shared branches

git push --force rewrites remote history. If anyone else has pulled the branch, their repo is now out of sync. Force pushing to main on a team is one of the fastest ways to cause chaos. The safe alternative is always git revert.

Quick Check
You pushed a commit to main that introduced a bug. What's the safest way to undo it?
Lesson 14Real-World

.gitignore & Best Practices

Not everything belongs in your repo. Build artifacts, secrets, IDE files, and operating system files should be excluded. The .gitignore file tells Git exactly what to ignore.

.gitignore — Java project example
# .gitignore file — place in your project root

# Compiled Java bytecode — never commit .class files
*.class
*.jar
target/
build/
out/

# IDE files — other developers use their own settings
.idea/
*.iml
.vscode/
*.eclipse

# Operating system files
.DS_Store
Thumbs.db

# NEVER commit secrets or credentials
*.env
config/secrets.properties
application-prod.properties

Best practices every developer follows

PracticeWhy
Commit early and oftenSmall commits are easier to understand, review, and revert
Never commit secretsGitHub repos are public by default; leaked API keys get abused within minutes
Write meaningful commit messagesYour team (and future you) will read these at 11pm debugging a production issue
Keep main always workingIf you break main, you block everyone. Use branches.
Pull before you pushPrevents rejected pushes and reduces conflicts
Delete merged branchesKeeps the branch list clean and focused
Add .gitignore at project startAdding it later means cleaning up already-committed junk
Review your diff before committingCatch debug prints, TODO comments, accidental changes
🔐
never commit passwords or API keys

Secrets committed to GitHub are permanently exposed — even if you delete the file later, the history still contains them. If you accidentally commit a secret, you must rotate it (generate a new one) immediately. Use environment variables or a .env file that's in your .gitignore.

Your Turn

Add a proper .gitignore

  • Go to gitignore.io (or github.com/github/gitignore) and generate a .gitignore for Java + your IDE
  • Add it to your Task Manager project
  • Run git status — notice how .class files and IDE folders are now hidden
  • Commit the .gitignore: "Add .gitignore for Java and IntelliJ"
Quick Check
You accidentally committed your config/secrets.properties file containing database passwords. What must you do?
Lesson 15Capstone

Capstone: Real Repo

Put everything together. You're going to take your Java Task Manager, give it a professional Git history, publish it to GitHub with a full README, and go through a complete feature-branch-and-PR workflow.

🎯
what you're building

A GitHub repository that any developer — or interviewer — could clone, understand, and contribute to. Clean commits. Good messages. Meaningful branches. A real README. This is what professional repos look like.

Part 1: clean up your history

1

Initialize the repo (if not done)

git init in your Task Manager folder. Add a .gitignore for Java.

2

Make atomic commits

Stage and commit each logical piece separately: the Task model, the TaskManager class, the file I/O, the README. Each commit should have a meaningful message.

3

Push to GitHub

Create a repo on GitHub, add remote, push. Your project is now live.

Part 2: feature branch workflow

4

Create a feature branch

Pick any improvement: sort by priority, search tasks, statistics report, or due date support. Branch: git switch -c feature/your-feature

5

Implement and commit

Make at least 2 commits on the branch, each representing a logical step.

6

Open a Pull Request

Push the branch, open a PR. Write a description: what it does, why you built it, how to test it.

7

Merge and clean up

Merge the PR. Pull locally. Delete the feature branch. Push the deletion.

Part 3: the README

A good README is the first thing anyone sees. Write one that includes:

  • Project title and one-sentence description
  • How to build and run it (javac *.java && java Main)
  • List of features
  • Example output / screenshot
  • What you'd build next
Final git log — what a clean history looks like
$ git log --oneline
f1a2b3c Merge pull request #3: Add task search
e9d8c7b Add case-insensitive keyword matching to searchTasks()
d6e5f4a Add searchTasks() method stub with tests
c3b2a1f Merge pull request #2: Add task sorting
b9a8f7e Sort by due date using Comparator.comparing()
a7b6c5d Add sort by priority — HIGH first
9e8d7c6 Merge pull request #1: Add file persistence
8f7e6d5 Add loadFromFile() with CSV parsing
7a6b5c4 Add saveToFile() using PrintWriter
6c5b4a3 Add TaskManager class with in-memory operations
5b4a3f2 Add Task model with CSV serialization
4a3b2c1 Add .gitignore for Java and IntelliJ
3f2e1d0 Add README with build instructions and feature list
🎉
what comes next

You now know every Git concept a junior developer needs on day one. Next on your roadmap: Maven/Gradle (managing dependencies and builds — your pom.xml goes in the repo), then JUnit 5 (test files live in the repo too), then Spring Boot (the whole project lives in GitHub with CI/CD running your tests automatically on every PR).

Roadmap