All Git Exercises

Create a Git repository and make your first commit

Description: Create a folder named my-notes, make it a Git repository, create a file notes.txt with some text, and save it in a first commit with the message “Add notes”.

Hint:

  • Use git init inside the folder.
  • A file must be staged with git add before the commit.

Solution

Terminal output

$ mkdir my-notes
$ cd my-notes
$ git init
Initialized empty Git repository in /home/robin/my-notes/.git/
$ echo "My first note" > notes.txt
$ git add notes.txt
$ git commit -m "Add notes"
[main (root-commit) 6927e03] Add notes
1 file changed, 1 insertion(+)
create mode 100644 notes.txt
$ git log –oneline
6927e03 (HEAD -> main) Add notes

How it works

  • git init creates the hidden .git folder, which makes the folder a repository.
  • git add stages the file, and git commit -m saves it with the message.
  • git log --oneline shows the new commit.

Read Git Init and Git Commit.

Check the status of files in a Git repository

Description: In a repository, create two files a.txt and b.txt, stage only a.txt, and show the status in the short format.

Hint:

  • Use git status -s for the short format.

Solution

Terminal output

$ mkdir status-demo
$ cd status-demo
$ git init -q
$ echo "a" > a.txt
$ echo "b" > b.txt
$ git add a.txt
$ git status -s
A a.txt
?? b.txt

How it works

  • A in the first column means a.txt is staged (added).
  • ?? means b.txt is untracked.

Read Git Status.

Stage only selected files and commit them separately

Description: You changed index.html, about.html and style.css. Make two commits: one with the two html files and one with only the css file.

Hint:

  • Stage the html files first with a pattern, commit, then stage the css file.

Solution

Terminal output

$ git add *.html
$ git commit -m "Update html pages"
[main 3f16559] Update html pages
2 files changed, 2 insertions(+), 2 deletions(-)
$ git add style.css
$ git commit -m "Update style"
[main 3ce526e] Update style
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log –oneline
3ce526e (HEAD -> main) Update style
3f16559 Update html pages
333d1be Start

How it works

  • The staging area lets us choose which files go in a commit.
  • Two small commits are easier to review than one big commit.

Read Git Add.

Show the commit history in one line per commit

Description: Show the history of a repository with one line per commit, and then show only the last 2 commits.

Hint:

  • Use --oneline and the option -n (or -2).

Solution

Terminal output

$ git log –oneline
a9b08d4 (HEAD -> main) Update file again
f95aab8 Update file
ad07eb3 Add file
$ git log –oneline -2
a9b08d4 (HEAD -> main) Update file again
f95aab8 Update file

How it works

  • --oneline shows the short hash and the title of each commit.
  • -2 limits the output to two commits.

Read Git Log.

See the changes of a file before staging and before commit

Description: Change a line in a tracked file. Show the change before staging, then stage the file and show the staged change.

Hint:

  • Plain git diff shows unstaged changes, and --staged shows staged changes.

Solution

Terminal output

$ printf "Tea\nMilk\n" > drinks.txt
$ git diff
diff –git a/drinks.txt b/drinks.txt
index 345af57..4227ee2 100644
— a/drinks.txt
+++ b/drinks.txt
@@ -1,2 +1,2 @@
Tea
-Coffee
+Milk
$ git add drinks.txt
$ git diff
$ git diff –staged
diff –git a/drinks.txt b/drinks.txt
index 345af57..4227ee2 100644
— a/drinks.txt
+++ b/drinks.txt
@@ -1,2 +1,2 @@
Tea
-Coffee
+Milk

How it works

  • Lines with - are removed and lines with + are added.
  • After git add, plain git diff is empty, because there is no unstaged change.

Read Git Diff.

Ignore all .log files with .gitignore

Description: Create debug.log, app.js and a folder build with a file inside. Make Git ignore all .log files and the build folder.

Hint:

  • Write the patterns *.log and build/ in a file named .gitignore.

Solution

Terminal output

$ mkdir ignore-demo
$ cd ignore-demo
$ git init -q
$ echo "log" > debug.log
$ echo "code" > app.js
$ mkdir build
$ echo "out" > build/out.js
$ printf "*.log\nbuild/\n" > .gitignore
$ git status -s
?? .gitignore
?? app.js
$ git check-ignore -v debug.log
.gitignore:1:*.log debug.log

How it works

  • Only .gitignore and app.js are shown. The log file and the build folder are hidden from Git.
  • git check-ignore -v tells which rule matched.

Read Git Ignore.

Create a new branch and switch to it

Description: Create a branch named feature-login, move to it, add a file login.html and commit it. Then show all branches.

Hint:

  • git switch -c creates a branch and moves to it.

Solution

Terminal output

$ git switch -c feature-login
Switched to a new branch 'feature-login'
$ echo "login" > login.html
$ git add login.html
$ git commit -m "Add login page"
[feature-login 001dfd4] Add login page
1 file changed, 1 insertion(+)
create mode 100644 login.html
$ git branch
* feature-login
main

How it works

  • The new branch starts from the commit where you were, so it has all the old files.
  • The new commit belongs only to feature-login, and main is not changed.

Read Git Branch and Git Checkout and Switch.

Merge a feature branch into main

Description: You have finished the work on feature-search. Merge it into main and show the history.

Hint:

  • Move to the target branch (main) first, then run git merge.

Solution

Terminal output

$ git switch main
Switched to branch 'main'
$ git merge feature-search
Updating a17f7f4..d37f093
Fast-forward
search.html | 1 +
1 file changed, 1 insertion(+)
create mode 100644 search.html
$ git log –oneline
d37f093 (HEAD -> main, feature-search) Add search page
a17f7f4 Add home

How it works

  • main had no new commits, so Git made a fast-forward merge and moved the pointer.
  • After the merge, the branch feature-search can be deleted.

Read Git Merge.

Resolve a merge conflict

Description: Both main and feature changed the first line of title.txt. Merge feature into main and solve the conflict by keeping the text “Learn Git Fast”.

Hint:

  • Edit the file to the final text, remove the markers, then git add and git commit.

Solution

Terminal output

$ git merge feature
Auto-merging title.txt
CONFLICT (content): Merge conflict in title.txt
Automatic merge failed; fix conflicts and then commit the result.
$ cat title.txt
<<<<<<< HEAD
Learn Git Easily
=======
Learn Git Quickly
>>>>>>> feature
$ echo "Learn Git Fast" > title.txt
$ git add title.txt
$ git commit -m "Merge feature and solve conflict"
[main b4f0e8e] Merge feature and solve conflict
$ git status
On branch main
nothing to commit, working tree clean

How it works

  • Git stops the merge and writes the markers in the file.
  • We replaced the file content with the final text, so no markers are left.
  • git add tells Git the conflict is solved, and the commit finishes the merge.

Read Git Merge Conflict.

Delete a merged branch

Description: The branch feature-menu is merged into main. Show the merged branches and delete it.

Hint:

  • git branch --merged lists merged branches. -d is the safe delete.

Solution

Terminal output

$ git branch –merged
feature-menu
* main
$ git branch -d feature-menu
Deleted branch feature-menu (was cda1bfa).
$ git branch
* main

How it works

  • The safe delete -d works only when the branch is merged. Otherwise Git refuses.
  • The commit is not lost, because it is already part of main.

Read Git Branch.

Rename a local branch

Description: Rename the branch fix-hedaer (a spelling mistake) to fix-header.

Hint:

  • Use git branch -m old new.

Solution

Terminal output

$ git branch -m fix-hedaer fix-header
$ git branch
fix-header
* main

How it works

  • -m means move (rename). Only the name changes, not the commits.
  • If the branch was pushed, push the new name and delete the old name on the remote.

Read Git Branch.

Unstage a file

Description: You staged secret.txt by mistake. Remove it from the staging area, but keep the file.

Hint:

  • Use git restore --staged.

Solution

Terminal output

$ git status -s
A secret.txt
$ git restore –staged secret.txt
$ git status -s
?? secret.txt
$ ls
app.txt
secret.txt

How it works

  • A (staged) changes to ?? (untracked), and the file stays in the folder.
  • Add the file to .gitignore so this does not happen again.

Read Git Restore.

Discard the changes of a file

Description: You edited config.txt and broke it. Discard your edit and get the last saved version back.

Hint:

  • Use git restore file. It cannot be undone, so be sure.

Solution

Terminal output

$ git status -s
M config.txt
$ git restore config.txt
$ git status -s
$ cat config.txt
theme=light

How it works

  • The file is replaced with the version from the last commit.
  • Changes that were never committed are lost, Git cannot bring them back.

Read Git Restore.

Undo the last commit but keep the changes

Description: You committed too early. Undo the last commit, but keep your changes ready in the staging area.

Hint:

  • HEAD~1 means one commit before HEAD.

Solution

Terminal output

$ git reset –soft HEAD~1
$ git log –oneline
2875ee0 (HEAD -> main) First
$ git status -s
M f.txt

How it works

  • The branch moves back one commit, and the commit “Second” is gone from the history.
  • M shows that the change is still staged, so you can finish your work and commit again.

Read Git Reset.

Revert a commit with git revert

Description: The commit “Add debug page” was a mistake, and it is already pushed. Undo it without changing the history.

Hint:

  • Use git revert with --no-edit to accept the default message.

Solution

Terminal output

$ git revert HEAD~1 –no-edit
[main a51ba50] Revert "Add debug page"
Date: Sat Jan 10 11:31:00 2026 +0000
1 file changed, 1 deletion(-)
delete mode 100644 debug.txt
$ git log –oneline
a51ba50 (HEAD -> main) Revert "Add debug page"
27e27e3 Add about page
f5f5ec5 Add debug page
95d0194 Add home page
$ ls
about.txt
home.txt

How it works

  • Git made a new commit which removes debug.txt.
  • The old commits are still in the history, so it is safe for shared branches.

Read Git Revert.

Fix the message of the last commit

Description: The last commit message is “Add contcat page”. Change it to “Add contact page”.

Hint:

  • Use git commit --amend -m.

Solution

Terminal output

$ git log –oneline
0e698a4 (HEAD -> main) Add contcat page
$ git commit –amend -m "Add contact page"
[main 6e54967] Add contact page
Date: Sat Jan 10 10:42:00 2026 +0000
1 file changed, 1 insertion(+)
create mode 100644 contact.html
$ git log –oneline
6e54967 (HEAD -> main) Add contact page

How it works

  • Amend replaces the last commit with a new commit, so the hash changes.
  • Do not amend a commit that is already pushed and used by others.

Read Git Commit Amend.

Stash your changes and bring them back

Description: You edited app.txt but must switch tasks. Put the changes aside, check that the folder is clean, and then bring the changes back.

Hint:

  • Use git stash and git stash pop.

Solution

Terminal output

$ echo "half done" >> app.txt
$ git stash
Saved working directory and index state WIP on main: 6b3a366 Add app
$ git status -s
$ git stash pop
On branch main
Changes not staged for commit:
(use "git add <file>…" to update what will be committed)
(use "git restore <file>…" to discard changes in working directory)
modified: app.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (0aac64f7d5bb638391472f0c078c4e2ca0506864)
$ cat app.txt
v1
half done

How it works

  • After git stash the folder is clean, so you can switch branches.
  • git stash pop applies the changes again and removes the stash entry.

Read Git Stash.

Create an annotated tag for a release

Description: Mark the latest commit as version v1.0 with the message “First release”. Show all tags and the details of the tag.

Hint:

  • Use git tag -a with -m.

Solution

Terminal output

$ git tag -a v1.0 -m "First release"
$ git tag
v1.0
$ git show v1.0 –no-patch
tag v1.0
Tagger: Robin Sharma <robin@example.com>
Date: Sat Jan 10 10:49:00 2026 +0000

First release

commit 378ffde0b81bbd9da251867b0d52884f32d49425 (HEAD -> main, tag: v1.0)
Author: Robin Sharma <robin@example.com>
Date: Sat Jan 10 10:42:00 2026 +0000

Add app

How it works

  • An annotated tag stores the tagger, date and message.
  • Tags are not pushed by git push. Use git push origin v1.0.

Read Git Tag.

Clone a repository, make a change and push it

Description: Clone the repository server.git into a folder my-work, add a file todo.txt, commit it and push it to the remote.

Hint:

  • A clone already has the remote origin, so a plain git push is enough.

Solution

Terminal output

$ git clone server.git my-work
Cloning into 'my-work'…
done.
$ cd my-work
$ echo "buy milk" > todo.txt
$ git add todo.txt
$ git commit -m "Add todo list"
[main 9eaf666] Add todo list
1 file changed, 1 insertion(+)
create mode 100644 todo.txt
$ git push
To /home/robin/server.git
4f5618b..9eaf666 main -> main

How it works

  • We used a local folder as the server. A GitHub URL works in the same way.
  • The last line shows that main was pushed to the remote main.

Read Git Clone and Git Push.

Get new changes from the remote with fetch and pull

Description: A teammate pushed a new commit. First check the new commits without changing your branch, and then update your branch.

Hint:

  • git fetch downloads without merging. git pull downloads and merges.

Solution

Terminal output

$ git fetch
From /home/robin/server
0f2bd93..66c2a05 main -> origin/main
$ git log HEAD..origin/main –oneline
66c2a05 (origin/main, origin/HEAD) Mate adds a file
$ git pull
Updating 0f2bd93..66c2a05
Fast-forward
mate.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 mate.txt
$ ls
app.txt
mate.txt

How it works

  • After the fetch, the commit is known as origin/main, but our branch did not move.
  • git pull then merged it (a fast-forward), and the new file is in our folder.

Read Git Fetch and Pull.