- 01.Git_The_Ultimate_Version_Control_System
- 02.Git_Workflow_Explained
- 03.Skipping_the_Staging_Area
- 04.Short_Status_View_And_Restore_History
- 05.Git_Log_Analysis_and_Filtering
- 06.View_Commits
- 07.Viewing_a_Commit_and_Understanding_Detached_HEAD_in_Git
- 08.Finding_Contributions
- 09.Restoring_a_Deleted_File
- 10.Finding_the_Author_of_a_Line_Blame
- 11.Git_Tagging
- 12.Git_Bisect_Finding_Bugs_Efficiently
- 13.Branching_01_Understanding_Git_Branching
- 14.Branching_02_Basic
- 15.Branching_03_Comparing_Branchesin_Git
- 16.Branching_04_Git_Stash_Operations
- 17.Branching_05_Understanding_Git_Merging
- 18.Branching_06_Fast_Forward_and_No_Fast_Forward_Merges
- 19.Branching_07_Git_Three_Way_Merge
A Version Control System (VCS) is a tool that helps developers track changes in their code over time, collaborate effectively, and revert to previous versions if needed.
- Centralized Version Control Systems (CVCS)
- A single central server holds the entire repository.
- Developers fetch and commit changes from/to this central repository.
- Examples:
- Subversion (SVN) ποΈ
- Team Foundation Server (TFS) πΌ
- Distributed Version Control Systems (DVCS)
- Each developer has a full copy of the repository on their local machine.
- No dependency on a central server; multiple copies ensure backup and flexibility.
- Examples:
- Git π
- Mercurial π
Git is widely used due to several key advantages:
- Free & Open Source ππ»
- Super Fast β‘
- Scalable π (Works for small and large projects)
- Branching & Merging Capabilities πΏπ
You can interact with Git using different methods:
- Command Line Interface (CLI) π₯οΈ - The most powerful and flexible way.
- Code Editors & IDEs ποΈ - Built-in Git support in VS Code, IntelliJ, etc.
- Graphical User Interfaces (GUI) π¨ - Visual tools like GitKraken, SourceTree.
- More control over Git features ποΈ
- GUI tools have limitations π«
- GUIs are not always available (e.g., when working on remote servers) π
To check if Git is installed on your system, run:
git --versionBefore using Git, you need to configure some settings:
git config --global user.name "Sithum Bimsara"
git config --global user.email "[email protected]"These commands set your name and email, which will be used in your commits.
If you prefer to edit Git messages in VS Code:
git config --global core.editor "code --wait"git config --global -eThis will open your global configuration file for editing.
Git settings are applied at different levels:
- System Level π’ (Applies to all users on the machine)
- Global Level π (Applies to all repositories for the current user)
- Local Level π (Applies only to the current repository)
Line endings refer to the special characters that indicate the end of a line in a text file. Different operating systems use different conventions:
- π₯οΈ Windows: Uses
\r\n(Carriage Return + Line Feed) - π macOS/Linux: Uses
\n(Line Feed only)
These differences can cause issues when sharing files across different operating systems, especially in version control systems like Git.
If you create a file example.txt on Windows and write:
Hello, World!
This is a test file.
Behind the scenes, the file is stored like this (with \r\n at the end of each line):
Hello, World!\r\n
This is a test file.\r\n
When the same file is opened on a Linux/macOS system, it may be interpreted differently because Linux expects only \n for line endings. If the system doesnβt handle \r\n properly, you might see something like:
Hello, World!^M
This is a test file.^M
(^M represents the extra \r character.)
This can cause issues in scripts, compilers, or version control.
Git automatically converts line endings based on your system and settings to prevent issues.
Run the following command to configure Git:
git config --global core.autocrlf true- β
Git will convert
\nto\r\nwhen checking out files. - β
Git will convert
\r\nback to\nwhen committing.
Run the following command:
git config --global core.autocrlf input- β
Git will convert
\r\nto\nwhen committing, but wonβt change anything on checkout.
Different line endings can cause issues when switching between operating systems. Git helps by normalizing line endings based on your settings, preventing unnecessary changes in repositories. Configuring Git properly ensures a smooth workflow when working across different environments.
-
For Windows:
git config --global core.autocrlf trueThis ensures
\r\n(Windows format) is converted to\n(Unix format) when committing. -
For macOS/Linux:
git config --global core.autocrlf input
This keeps line endings unchanged in macOS/Linux but converts
\r\nto\nwhen committing.
π‘ Now you're ready to start using Git efficiently! π
Git follows a structured workflow to track changes efficiently. The process involves three main areas:
- Working Directory π - The area where you modify files.
- Staging Area (Index) ποΈ - Where changes are added before committing.
- Repository ποΈ - Where committed changes are permanently stored.
git add file1 file2β
Moves file1 and file2 from the working directory to the staging area.
git commit -m "Initial Commit"β Saves the staged files into the repository.
If you modify file1, the changes remain only in the working directory, not in the staging area or repository.
git add file1β
Moves the modified file1 to the staging area.
git commit -m "Fixed the bug in file1"β
Saves the modified file1 to the repository.
If you delete file2 from the working directory, it still exists in the staging area.
To remove it from staging:
git add file2β
Now file2 is marked for deletion.
git commit -m "Removed file2"β
Permanently removes file2 from the repository.
To start tracking a project with Git:
mkdir Moon # Create a new directory
cd Moon # Navigate into the directory
git init # Initialize Git in the directoryβ Output:
Initialized empty Git repository in C:/Users/User/Desktop/projects/GIT MOSH/Moon/.git/
π Viewing Hidden Files
By default, .git (Git's hidden directory) is not shown.
dir # This will not show .gitdir /a # Shows .gitls # This will not show .gitls -a # Shows .gitTo explore Gitβs internal structure:
explorer .git # Windows
open .git # macOS/Linuxecho hello > file1.txt
echo hello > file2.txt
git statusπ΄ Output: (Untracked files in red)
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
file1.txt
file2.txt
git add file1.txt file2.txt
git statusπ’ Output: (Files in green, ready to commit)
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: file1.txt
new file: file2.txt
echo world >> file1.txt
git statusπ΄ Output: (File1 modified but not staged in red)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: file1.txt
git commit -m "Initial Commit"β Stores changes in the repository.
git add .
git statusπ’ Output: (File1 modified and staged in green)
Changes to be committed:
modified: file1.txt
git commitβοΈ This command opens a text editor (VS Code, Vim, etc.) to enter a descriptive commit message.
[master cdab869] A short description.
1 file changed, 1 insertion(+)
π Now you understand the full Git workflow! π
echo test >> file1.txtThis appends "test" to file1.txt.
git commit -a -m "Fix the bug"git commit -am "Fix the bug"[master b0a24b1] Fix the bug
1 file changed, 1 insertion(+)
The -a flag automatically stages and commits all tracked files, skipping the staging area.
del file2.txtrm file2.txtgit statusChanges not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: file2.txt
git ls-filesfile1.txt
file2.txt
git add file2.txtgit ls-filesfile1.txt
git commit -m "Remove file2.txt"git rm file2.txtrm 'file2.txt'
git commit -m "Remove file2.txt"dir03/14/2025 02:45 PM <DIR> .
03/14/2025 02:45 PM <DIR> ..
0 File(s) 0 bytes
2 Dir(s) 8,479,490,048 bytes free
As you can see no files in the working directory.
git statusOn branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: file1.txt
rename file1.txt main.jsmv file1.txt main.jsgit statusOn branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: file1.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
main.js
git add file1.txt main.jsgit statusOn branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: file1.txt -> main.js
Then git will identify this as a file renaming.
git commit -m "Refactor code"β Alternative Approach to directly rename a file both working directory and staging area in one go:
git mv main.js file1.txtgit statusOn branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: main.js -> file1.txt
mkdir logsecho "hello" > logs/dev.loggit statusOn branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
logs/
nothing added to commit but untracked files present (use "git add" to track)
echo logs/ > .gitignoregit add .gitignoregit commit -m "Add gitignore"When we accidently add a unwanted file into staging area, we should have to remove it from staging area too, otherwise if we add that file to .gitignore that files also will be go to staging area, although that file name also included in .gitignore.
mkdir binecho "hello" > bin/app.bingit add .git commit -m "Add bin"echo bin/ > .gitignoregit commit -m "Include bin directory to .gitignore"echo hellworld >> bin\app.bin()git statusOn branch master
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: bin/app.bin
no changes added to commit (use "git add" and/or "git commit -a")
As you can see the above output our intension was not completed yet, If we want to don't add the changes we make to bin folder to staging area , git is still tracking that folder.
git ls-files.gitignore
bin/app.bin
file1.txt
logs/dev.log
git rm --cached -r bin/git ls-files.gitignore
file1.txt
logs/dev.log
git statusOn branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
deleted: bin/app.bin
git commit -m "Remove the bin directory that was accidentally committed"?? file0.js
A file1.js
AM file2.js
??β Untracked files (new files not yet added to Git)Aβ Newly added file to stagingAMβ A file that was added (A) and then modified (M) before committing- Red
Mβ Modified file but not yet staged - Green
Mβ Modified file that has been staged - Green
Aβ Newly added file to the staging area
diff --git a/file1.js b/file1.js
index 7436f3f..6fdbffe 100644
--- a/file1.js
+++ b/file1.js
@@ -3,3 +3,5 @@ hello
hello
hello
hello
+hello
+hello
diff --git a/file1.js b/file1.jsβ Shows differences between two versions offile1.jsindex 7436f3f..6fdbffe 100644β SHA index of the file before and after--- a/file1.jsβ Old version+++ b/file1.jsβ New version@@ -3,3 +3,5 @@β Context of the changes+helloβ New lines added
index 6fdbffe..d29bf5e 100644
--- a/file1.js
+++ b/file1.js
@@ -5,3 +5,5 @@ hello
hello
hello
hello
+hello
+hello
- Shows changes in the working directory (unstaged changes)
git config --global diff.tool vscode
git config --global difftool.vscode.cmd "code --wait --diff $LOCAL $REMOTE"git config --global -e[user]
name = Sithum Bimsara
email = [email protected]
[core]
editor = code --wait
autocrlf = true
[diff]
tool = vscode
[difftool "vscode"]
cmd = code --wait --diff $LOCAL $REMOTE
[safe]
directory = C:/Users/User/Desktop/projects/50+GenAIProjects
[user]β User information[core]β Default editor settings[diff]β Specifies VSCode as the default diff tool[difftool "vscode"]β Command to launch VSCode in diff mode
git difftoolπΉ Purpose:
Compares the working directory with the latest committed version (HEAD). Opens an external diff tool (e.g., VS Code, Meld, Beyond Compare).
πΉ Example Usage:
If you modified file1.txt but haven't committed it yet, running:
git difftoolwill open file1.txt in your configured diff tool, showing changes against the last committed version.
git difftool --stagedπΉ Purpose:
Compares staged changes (added with git add) against the last committed version. Useful for reviewing changes before committing.
πΉ Example Usage:
Modify a file:
echo "sky" >> file1.txt
echo "ocean" >> file1.txtStage it:
git add file1.txtRun:
git difftool --stagedThis shows differences between staged changes and the last commit.
commit 2164f6310e417ad5e988be02814e268f515683e2 (HEAD -> master)
Author: Sithum Bimsara <[email protected]>
Date: Sat Mar 15 09:10:29 2025 +0530
File 1 changed
commit 6e3f75779d40f821b5a831845e51d2e1dff1b918
Author: Sithum Bimsara <[email protected]>
Date: Sat Mar 15 09:06:24 2025 +0530
File added
commit <hash>β Unique ID of the commitHEAD -> masterβ Current branchAuthorβ Committer's detailsDateβ Timestamp of the commitMessageβ Short description of the commit
- Displays commits in a compact format
2164f63 (HEAD -> master) File 1 changed
6e3f757 File added
- Shows detailed information about a specific commit
- Shows the latest commit
- Shows the commit before the latest one
- Lists files and directories in a previous commit
Git is a distributed version control system that stores data as a series of objects in a repository's .git/objects directory. These objects help track changes efficiently.
Git objects include:
- Commits β Record of changes
- Blobs β Store file content
- Trees β Store directory structures
- Tags β References to specific commits
- Moves files from staging to the working directory
git restore --staged file1.js
git restore --staged file1.js file2.txt
git restore --staged *.txt
git restore --staged .
git status -sgit restore file1.js
git restore .
git status -s
git clean -fd
git status -sgit restore file1.jsβ Discards changes infile1.jsgit restore .β Discards all changesgit clean -fdβ Removes untracked files and directories
git restore --source=HEAD~1 file1.js- Restores
file1.jsto its previous commit version
π οΈ This guide covers essential Git operations to help you manage your project efficiently! π
This guide provides a comprehensive understanding of Git log commands and their outputs, ensuring a clear and structured approach to Git history tracking.
Output:
commit 16eab60108a23d7adb5004fc2d18285db0fa2a70 (HEAD -> master)
Author: Sithum Bimsara <[email protected]>
Date: Sat Mar 15 11:51:35 2025 +0530
Hello Sithum World added
commit 14f4275fd928bbf5f06b918496461a05ba506419
Author: Sithum Bimsara <[email protected]>
Date: Sat Mar 15 11:49:58 2025 +0530
Deleted all
π Explanation:
- Displays the commit history in full detail.
- Each commit includes a commit hash, author, date, and commit message.
Output:
16eab60 (HEAD -> master) Hello Sithum World added
14f4275 Deleted all
da3d1b1 2worlds added
2164f63 File 1 changed
6e3f757 File added
π Explanation:
- Shows a summarized one-line version of the commit history.
- The commit hash is shortened for better readability.
Output:
16eab60 (HEAD -> master) Hello Sithum World added
file1.js | 3 +++
1 file changed, 3 insertions(+)
14f4275 Deleted all
file1.js | 9 ---------
file2.js | 3 +++
2 files changed, 3 insertions(+), 9 deletions(-)
π Explanation:
- Displays the number of files changed, insertions (
+), and deletions (-) in each commit.
Output:
commit 16eab60108a23d7adb5004fc2d18285db0fa2a70 (HEAD -> master)
Author: Sithum Bimsara <[email protected]>
Date: Sat Mar 15 11:51:35 2025 +0530
Hello Sithum World added
file1.js | 3 +++
1 file changed, 3 insertions(+)
π Explanation:
- Displays detailed commit history with file changes and statistics.
- Shows the last 3 commits.
- Filters commits by author.
- Displays commits made after a specific date.
- Filters commits with a case-sensitive search in messages.
- Displays commits that have added or removed "hello".
- Shows commit history for file1.js only.
Output:
Sithum Bimsara commited 16eab60 on Sat Mar 15 11:51:35 2025 +0530
Sithum Bimsara commited 14f4275 on Sat Mar 15 11:49:58 2025 +0530
π Explanation:
- Custom formatting using
%an(author),%h(short hash), and%cd(commit date).
π Explanation:
- Adds green color to the author name for better readability.
Git aliases allow us to create shortcuts for commonly used commands.
git config --global alias.lg "log --pretty=format:'%an committed %h'"β
This command sets git lg as a shortcut for viewing commit logs in a compact format, displaying the author's name and commit hash.
git lgπ Output:
Sithum Bimsara committed 16eab60
Sithum Bimsara committed 14f4275
Sithum Bimsara committed da3d1b1
Sithum Bimsara committed 2164f63
Sithum Bimsara committed 6e3f757
git config --global alias.unstage "restore --staged ."β
Now we can use git unstage instead of git restore --staged . to unstage files easily.
git show HEAD~2β This command moves two commits back from the latest commit (HEAD) and shows the details.
git show HEAD~2:path/to/fileβ This command shows the state of a specific file at a commit two steps back.
π How to declare the path?
- The path should be relative to the Git repository root.
- Example:
git show HEAD~2:src/index.jsgit show HEAD~2 --name-onlyπ Output:
commit 14f4275fd928bbf5f06b918496461a05ba506419
Author: Sithum Bimsara <[email protected]>
Date: Sat Mar 15 11:49:58 2025 +0530
Deleted all
file1.js
file2.js
git show HEAD~2 --name-statusπ Output:
commit 14f4275fd928bbf5f06b918496461a05ba506419
Author: Sithum Bimsara <[email protected]>
Date: Sat Mar 15 11:49:58 2025 +0530
Deleted all
M file1.js
M file2.js
βΉοΈ M means the file was modified.
git diff HEAD~2 HEADπ Output:
diff --git a/file1.js b/file1.js
index 470dc38..39db52e 100644
--- a/file1.js
+++ b/file1.js
@@ -1,3 +1,4 @@
Hello
Sithum
-World
\ No newline at end of file
+World
+Bimsara
\ No newline at end of file
diff --git a/file2.js b/file2.js
index 8daf0ad..2e4eee7 100644
--- a/file2.js
+++ b/file2.js
@@ -3,3 +3,4 @@
world
world
hello
hello
+James
git diff HEAD~2 HEAD file1.jsπ Output:
diff --git a/file1.js b/file1.js
index 470dc38..39db52e 100644
--- a/file1.js
+++ b/file1.js
@@ -1,3 +1,4 @@
Hello
Sithum
-World
\ No newline at end of file
+World
+Bimsara
\ No newline at end of file
git diff HEAD~2 HEAD --name-onlyπ Output:
file1.js
file2.js
git diff HEAD~2 HEAD --name-statusπ Output:
M file1.js
M file2.js
β
M indicates the files were modified.
When working with Git, sometimes you want to view the complete snapshot of your project at a specific point in time. This is done by checking out a given commit. This action restores your working directory to the snapshot stored in that commit, allowing you to see how your project looked at that moment.
# Copy the commit ID from the log
$ git log
# Run the checkout command
$ git checkout <commit-id>π Output
Note: switching to '14f4275'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 14f4275 Deleted all
When you check out a commit, Git warns you that you are in a detached HEAD state. This sounds intimidating, but itβs actually simple.
**Now you use git log --online you only can view only the changes before the above commit.
π Output
14f4275 (HEAD) Deleted all
da3d1b1 2worlds added
2164f63 File 1 changed
6e3f757 File added
π To View All Commits (Including Hidden Ones)
$ git log --oneline --allπ Output
4ce9343 (master) All commited
df9b461 James added to file2
befda4c Bimsara added to file1
16eab60 Hello Sithum World added
14f4275 (HEAD) Deleted all
da3d1b1 2worlds added
2164f63 File 1 changed
6e3f757 File added
**But as you can see in the output HEAD and master are seperated.
- Each commit points to the previous commit, forming a chain.
- These commits are part of the master branch, the main line of work.
- Git represents branches using a pointer. For example, the master pointer points to the latest commit.
- The HEAD pointer tells Git which branch you're currently working on.
- When you create new commits, both the master pointer and HEAD pointer move forward.
- When you check out a specific commit, the HEAD pointer moves to that commit, but itβs no longer attached to any branch. This is called the detached HEAD state.
- You can view the code at that point in time.
- β Do NOT create new commits because those commits will be unreachable and eventually deleted by Git to save space.
If you create a new commit in the detached HEAD state:
- The commit is not part of any branch.
- It becomes a dangling commit and will be deleted by Git during garbage collection.
To exit the detached HEAD state and return to the master branch:
$ git checkout masterπ Viewing All Commits (Including Hidden Ones)
$ git log --oneline --allmaster ----> commit1 ----> commit2 ----> commit3 ----> commit4 (HEAD)
| Action | State |
|---|---|
| Checkout a commit | Detached HEAD |
| Create new commits | Risk of losing them |
| Return to master branch | git checkout master |
| View all commits | git log --oneline --all |
β Key Takeaway: Use detached HEAD to explore past code, not to make changes!
Git provides the git shortlog command to summarize contributions made by each author. Hereβs an example:
git shortlogSithum-Bimsara (4):
Create README.md
Update README.md
Merge pull request #19 from Sithum-Bimsara/feature/backend/v1
Merge pull request #21 from Sithum-Bimsara/front-end
Dulitha Perera (3):
Merge pull request #1 from Sithum-Bimsara/feature/backend/v1
Add functions to feedback model
Fix an error and create feedback controller
Sasmitha Uvindu Jayasinghe (3):
Started creating front end
Merge pull request #11 from Sithum-Bimsara/feature/backend/v1
updated the headergit shortlog -n -s 17 Sithum Bimsara
13 Sasmitha Uvindu Jayasinghe
8 Dulitha PereraThe -n option sorts authors by the number of commits, and -s shows only the commit count.
If you accidentally delete a file in Git, you can restore it. Letβs see a real-world scenario:
git rm file1.jsrm 'file1.js'git commit -m "Remove file1.js"git log --oneline -- file1.js5f28a5d (HEAD -> master) Remove file1.js
4ce9343 All committed
...git checkout 4ce9343 file1.jsgit commit -m "Restore file1.js"git statusOn branch master
nothing to commit, working tree cleanThe git blame command helps identify who made changes to specific lines of a file.
git blame file1.js76f9ff77 (Sithum Bimsara 2025-03-17 22:12:03 +0530 1) Hello
76f9ff77 (Sithum Bimsara 2025-03-17 22:12:03 +0530 2) Sithum
76f9ff77 (Sithum Bimsara 2025-03-17 22:12:03 +0530 3) WorldYou can also check with email details:
git blame -e file1.js76f9ff77 (<[email protected]> 2025-03-17 22:12:03 +0530 1) Hellogit tag v1.0 14f4275git tagv1.0git show v1.0git tag -a v1.1 -m "My version 1.1"git tag -nv1.0 Deleted all
v1.1 My version 1.1git checkout v1.0git tag -d v1.1Deleted tag 'v1.1' (was 464b228)This provides a comprehensive understanding of commonly used Git operations, making version control more efficient and reliable. π
Git bisect is a powerful tool that helps developers quickly find the commit that introduced a bug in their application. Instead of checking out each commit manually, git bisect allows us to use a binary search algorithm to pinpoint the faulty commit efficiently.
git log --onelineOutput:
76f9ff7 (HEAD -> master) Restore file1.js
5f28a5d Remove file1.js
4ce9343 All commited
df9b461 James added to file2
befda4c Bimsara added to file1
16eab60 Hello Sithum World added
14f4275 (tag: v1.0) Deleted all
da3d1b1 2worlds added
2164f63 File 1 changed
6e3f757 File added
π This command lists all commits in a compact format (one line per commit). The most recent commit appears at the top.
git bisect startOutput:
status: waiting for both good and bad commits
π This initializes the bisect process, setting up Git to find the commit where the bug was introduced.
git bisect badOutput:
status: waiting for good commit(s), bad commit known
π¨ This tells Git that the current commit has a bug.
git bisect good 6e3f757Output:
Bisecting: 4 revisions left to test after this (roughly 2 steps)
[16eab60108a23d7adb5004fc2d18285db0fa2a70] Hello Sithum World added
π΅οΈββοΈ This tells Git that the commit 6e3f757 was before the bug appeared, helping it narrow down the search.
git log --onelineOutput:
16eab60 (HEAD) Hello Sithum World added
14f4275 (tag: v1.0) Deleted all
da3d1b1 2worlds added
2164f63 File 1 changed
6e3f757 File added
π This shows the current state of commits after the bisect operation.
git bisect goodOutput:
Bisecting: 2 revisions left to test after this (roughly 1 step)
[df9b461e3b51bac8cbdbe680fd53f1ef02b44197] James added to file2
π This tells Git that this commit is still good, further narrowing down the range.
git bisect goodOutput:
Bisecting: 0 revisions left to test after this (roughly 1 step)
[5f28a5d163868c446c64568c2da623796319035f] Remove file1.js
π Now only one commit is left to check.
git bisect badOutput:
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[4ce93435d5eac9900d11105771b863aff982ab84] All commited
π This confirms that the commit 4ce9343 introduced the bug.
git bisect resetOutput:
Previous HEAD position was 4ce9343 All commited
Switched to branch 'master'
β This restores the repository to its original state before the bisect operation.
-
Start the Bisect Process
git bisect startinitializes the bisect operation.
-
Mark a Bad Commit β
git bisect badtells Git the current commit has the bug.
-
Mark a Good Commit β
git bisect good <commit_hash>tells Git where the bug was not present.
-
Binary Search π
- Git will checkout a middle commit.
- You test if the bug is present.
- If the bug exists, mark it as
git bisect bad. - If the bug does not exist, mark it as
git bisect good. - Repeat until Git finds the first bad commit.
-
Identifying the Buggy Commit π οΈ
- Git pinpoints the exact commit where the issue was introduced.
-
Reset to Normal State
git bisect resetbrings the repository back to normal.
Using git bisect, we efficiently pinpointed the commit where the bug originated, saving time and effort compared to manually checking each commit. This technique is invaluable when debugging large projects.
Branching allows us to diverge from the main line of work and work on something else in isolation. Conceptually, a branch is like a separate workspace.
- We have a main workspace called
master(ormain). - We can create another workspace (branch) to work on a new feature separately.
- While developing this new feature, the code might become unstable, so we don't want to release it immediately.
- Once development is done, we test the code, fix all bugs, and then bring the changes back into
master. - This process is called merging.
- Keeps the main code stable so it can be released anytime.
- Prevents the main line of work from getting messed up.
- Helps new team members start on a stable code base.
Git handles branches differently from other version control systems like Subversion.
- When creating a new branch, Subversion copies the entire working directory.
- If a project has hundreds or thousands of files, this can take time and waste disk space.
- Slow and inefficient, leading many developers to dislike branching in SVN.
- A branch in Git is just a pointer to a commit.
- The
masterbranch is simply a pointer to the last commit in the main line of work. - As new commits are made, Git automatically moves this pointer forward.
- Creating a branch in Git is almost instant because it's just a small reference (a 40-byte commit ID).
-
Creating a Branch π
- Git creates a new pointer that can move around.
- This pointer is a tiny file storing the commit ID.
-
Making New Commits π
- When we switch to a branch and commit, Git moves this new pointer forward.
- The
masterpointer stays unchanged until we merge the changes.
-
Switching Branches π
- When switching back to
master, Git resets the working directory to the snapshot stored in the latest commit ofmaster. - Only one working directory exists at a time.
- When switching back to
-
Tracking the Current Branch π
- Git uses a special pointer called
HEAD. HEADis another small file storing the name of the branch we're currently working on.- When we switch branches, Git updates
HEADto point to the target branch.
- Git uses a special pointer called
β Branching keeps the main code stable. β Git branches are fast and lightweight. β Merging brings changes back to the main branch. β HEAD pointer tracks the active branch.
Throughout this section, you will learn everything needed to work with Git branches efficiently. π
Git is a powerful tool for version control, and managing branches effectively is a crucial skill. In this guide, we will walk through the process of creating, switching, renaming, modifying, and deleting branches while fixing a bug. We will also examine the necessary Git commands and their outputs to ensure a smooth workflow.
When we receive a bug report, the best practice is to create a new branch to isolate the fix. We do this using:
$ git branch bugfixTo list all branches and see the currently active branch:
$ git branchOutput:
bugfix
* master
The asterisk (*) indicates that we are on the master branch.
There are two ways to switch branches:
1οΈβ£ Old method (deprecated but still works):
$ git checkout bugfix2οΈβ£ New recommended method:
$ git switch bugfixOutput:
Switched to branch 'bugfix'
A generic name like bugfix is not very descriptive. Itβs better to use something specific:
$ git branch -m bugfix bugfix/signup-formOutput:
Branch renamed to 'bugfix/signup-form'
Let's open the file audience.txt and make some modifications.
Who are you?
My name is Sithum Bimsara.
I'm 22 years old.
to
"Who are you?"
======================================
My name is Sithum Wickramanayake
After saving the changes, we check the status:
$ git statusOutput:
On branch bugfix/signup-form
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: audience.txt
To stage the modified file:
$ git add audience.txtTo commit with a message:
$ git commit -m "Fix bug that prevented users from signing up"Output:
[bugfix/signup-form 8f19a63] Fix bug that prevented users from signing up
1 file changed, 3 insertions(+), 1 deletion(-)
To see our commits in a compact format:
$ git log --onelineOutput:
8f19a63 (HEAD -> bugfix/signup-form) Fix bug that prevented users from signing up
76f9ff7 Restore file1.js
5f28a5d Remove file1.js
Notice that HEAD is pointing to bugfix/signup-form, meaning we are currently on this branch.
Now, letβs go back to the master branch:
$ git switch masterOutput:
Switched to branch 'master'
If we open audience.txt again, weβll see the old version because our changes exist only in bugfix/signup-form.
To see commits across all branches:
$ git log --oneline --allOutput:
99a39d7 (bugfix/signup-form) Fix the bug in signup
c38d43f (HEAD -> master) Deleted audience.txt
8f19a63 Audience.txt added
76f9ff7 Restore file1.js
5f28a5d Remove file1.js
4ce9343 All commited
df9b461 James added to file2
befda4c Bimsara added to file1
16eab60 Hello Sithum World added
14f4275 (tag: v1.0) Deleted all
da3d1b1 2worlds added
2164f63 File 1 changed
6e3f757 File added
Once we merge the bugfix/signup-form branch into master, we no longer need it.
Attempting to delete it normally:
$ git branch -d bugfix/signup-formOutput (error message if branch is not merged yet):
error: The branch 'bugfix/signup-form' is not fully merged.
To force delete it:
$ git branch -D bugfix/signup-formOutput:
Deleted branch bugfix/signup-form (was 76f9ff7).
In this guide, we learned how to: β Create and switch branches β Rename branches for better clarity β Make changes and commit them β View commit logs β Delete branches safely
This workflow helps us maintain a clean and organized Git history while preventing accidental commits to the wrong branch. π
When working with Git, it's crucial to compare branches before merging them into the main branch (e.g., master). In this guide, weβll explore various ways to check how a branch differs from master using Git commands.
Before merging a branch, we need to identify the commits that exist in the feature or bugfix branch but not in master. We use the following command:
$ git log master..bugfix/signup-formcommit fc89881a9248f431c31e97ed56e8091db8b99e3f (bugfix/signup-form)
Author: Sithum Bimsara <[email protected]>
Date: Sun Mar 23 02:06:47 2025 +0530
Changed audience.txt from bugfix/signup-form branch- This command lists all the commits in
bugfix/signup-formthat are not inmaster. - In this case, there is one commit, but if there were more, all of them would be listed.
- The
master..bugfix/signup-formsyntax means: "Show me all commits inbugfix/signup-formthatmasterdoesnβt have."
π If you want a more concise output, you can use:
$ git log --oneline master..bugfix/signup-formIf we want to see the actual file changes instead of just commit messages, we use:
$ git diff master..bugfix/signup-formdiff --git a/audience.txt b/audience.txt
index a9fd72c..1e80bad 100644
--- a/audience.txt
+++ b/audience.txt
@@ -1,7 +1,7 @@
Who are you?
+==========================
+My name is Sithum Wickramanayake
-My name is Sithum Bimsara
-I'm 22 years old- The
+lines indicate new additions. - The
-lines indicate removals. - This tells us that the
audience.txtfile has been modified:- The old name "Sithum Bimsara" was changed to "Sithum Wickramanayake".
- "I'm 22 years old" was removed.
π If we are currently on master, we can simplify the command:
$ git diff bugfix/signup-formSometimes, we donβt need to see the detailed changes, just the list of modified files. We use:
$ git diff --name-status bugfix/signup-formM audience.txt- The
Mmeans the file audience.txt has been modified. - This helps quickly identify which files will be changed when merging the branch.
| Command | Purpose |
|---|---|
git log master..branch |
Shows commits in branch but not in master |
git log --oneline master..branch |
Shows commits in a compact format |
git diff master..branch |
Shows line-by-line changes between master and branch |
git diff branch |
Shorter version if on master |
git diff --name-status branch |
Lists only the changed files |
By using these commands, you can effectively review the changes in a branch before merging it into master. π
When working with Git, sometimes we have local changes that we haven't committed yet, but we need to switch branches. Git prevents switching in such cases to avoid losing changes. In this guide, we will explore how to use Git Stash to temporarily save changes and retrieve them later.
To check which branches exist and which one we are currently on, we use:
$ git branchOutput:
bugfix/signup-form
* master
Here, master is the active branch (* indicates the current branch).
If we try to switch branches without committing or stashing local changes, we get an error:
$ git switch bugfix/signup-formError Output:
error: Your local changes to the following files would be overwritten by checkout:
audience.txt
Please commit your changes or stash them before you switch branches.
Aborting
Since we donβt want to commit the changes yet, we will stash them.
To temporarily save changes, use the git stash push command:
$ git stash push -m "New tax rules"Output:
Saved working directory and index state On master: New tax rules
By default, untracked files are not included in the stash. Let's create a new file:
$ echo hello > newfile.txtCheck the status:
$ git status -sOutput:
?? newfile.txt
To stash all files, including untracked ones:
$ git stash push -am "My new stash"Output:
Saved working directory and index state On master: My new stash
To view stored stashes:
$ git stash listOutput:
stash@{0}: On master: My new stash
stash@{1}: On master: New tax rules
Now we can switch to another branch without losing changes:
$ git switch bugfix/signup-formOutput:
Switched to branch 'bugfix/signup-form'
We can switch back to master anytime:
$ git switch masterOutput:
Switched to branch 'master'
Before applying a stash, check its contents:
$ git stash show stash@{1}Output:
audience.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
The same output can be obtained using:
$ git stash show 1To apply a specific stash to the working directory:
$ git stash apply 1Output:
On branch master
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: audience.txt
Once a stash is applied, we can delete it:
$ git stash drop 1Output:
Dropped refs/stash@{1} (f92bb35ab1d8197db347e9fb3a47aee0b8221e3e)
To verify:
$ git stash listOutput:
stash@{0}: On master: My new stash
To remove all stashes at once:
$ git stash clearAfter this, running git stash list will return nothing.
Git Stash is a powerful tool that allows you to temporarily store changes and retrieve them later without committing. It helps in switching branches safely without losing work. Now you can confidently stash, apply, drop, and clear stashes in your projects! π
Merging is the process of integrating changes from one branch into another. In Git, we have two types of merges:
- Fast Forward Merges π
- Three-Way Merges π
Let's explore both with real-world examples! π§
Imagine we have a master branch with three commits. We create a new branch called bugfix. In Git, a branch is just a pointer to a commit. Initially, both master and bugfix point to the same commit.
# Check the current branches
$ git branch
* master
# Create and switch to a new branch
$ git checkout -b bugfix
Switched to a new branch 'bugfix'Now, we make a couple of commits on the bugfix branch.
# Make changes and commit
$ echo "Fixing a bug" > bug.txt
$ git add bug.txt
$ git commit -m "Fixed a bug"
# Make another change
$ echo "Another fix" >> bug.txt
$ git commit -am "Another fix applied"At this point, the bugfix branch is ahead of master. Since the branches haven't diverged, merging is straightforward.
# Switch back to master
$ git checkout master
# Merge the bugfix branch
$ git merge bugfixπΉ What happens?
Since thereβs a direct linear path from bugfix to master, Git moves the master pointer forward without creating a new commit. This is a Fast Forward Merge.
Updating 3f7a6c2..9b9cbb1
Fast-forward
bug.txt | 2 ++
1 file changed, 2 insertions(+)Once merged, we can delete the bugfix branch.
$ git branch -d bugfix
Deleted branch bugfix.β Fast Forward Merge is simple and efficient because no extra commits are created.
Now, letβs explore a case where branches have diverged.
# Create a new branch and switch to it
$ git checkout -b bugfixMake some changes in the bugfix branch.
$ echo "Bug fixed" > bug.txt
$ git add bug.txt
$ git commit -m "Bug fix implemented"Now, before merging, we switch to master and make another change.
# Switch to master
$ git checkout master
# Modify another file
$ echo "Feature update" > feature.txt
$ git add feature.txt
$ git commit -m "Feature update added"At this point, master and bugfix have different changes. If we try to merge, Git cannot fast forward because master has unique commits.
# Merge the bugfix branch into master
$ git merge bugfixπΉ What happens?
Since master and bugfix have diverged, Git creates a new commit that combines changes from both branches. This is a Three-Way Merge.
Merge made by the 'recursive' strategy.
bug.txt | 1 +
feature.txt | 1 +
2 files changed, 2 insertions(+)Git automatically resolves the changes and generates a merge commit.
π Why is it called a Three-Way Merge? It involves three commits:
- The common ancestor (original commit before branching)
- The
masterbranch tip - The
bugfixbranch tip
Git looks at these three snapshots and decides how to combine them.
β Three-Way Merge ensures that both branches' changes are preserved.
- Fast Forward Merge happens when branches haven't diverged. Git simply moves the pointer forward.
- Three-Way Merge happens when branches have diverged. Git creates a new commit to merge changes.
π― Understanding when to use each type of merge is crucial for maintaining a clean Git history!
This notebook covers the concepts of Fast Forward (FF) Merges and No Fast Forward (No-FF) Merges in Git. We will explore how these merge strategies work, their advantages and disadvantages, and how to configure them.
Before performing any merge operation, it's good practice to check the log with a graphical representation to see how branches diverge.
git log --oneline --all --graph* f76e273 (HEAD -> bugfix/signup-form) Fix the bug that protects users from signing up
* 8797d0e (master) TOC.txt added
* a2410e0 Audience.txt added
* 68a073e File2 added
* c43539f File1 added
π Observation: The bugfix/signup-form branch is ahead of master by one commit.
Since master has not diverged from bugfix/signup-form, we can merge using a Fast Forward Merge.
git switch masterOutput:
Switched to branch 'master'
git merge bugfix/signup-formOutput:
Updating 8797d0e..f76e273
Fast-forward
toc.txt | 1 +
1 file changed, 1 insertion(+)
β
Fast Forward Merge Complete: The master branch now points to f76e273, creating a linear history.
To disable Fast Forward merging and retain a merge commit, use --no-ff.
git switch -C bugfix/login-formOutput:
Switched to a new branch 'bugfix/login-form'
code toc.txt
git add toc.txt
git commit -m "Update toc.txt"Output:
[bugfix/login-form 8538e99] Update toc.txt
1 file changed, 1 insertion(+), 1 deletion(-)
git switch master
git merge --no-ff bugfix/login-formOutput:
Merge made by the 'ort' strategy.
toc.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
git log --oneline --all --graphOutput:
* ff8fcb1 (HEAD -> master) Merge branch 'bugfix/login-form'
|\
| * 8538e99 (bugfix/login-form) Update toc.txt
|/
* f76e273 (bugfix/signup-form) Fix the bug that protects users from signing up
* 8797d0e TOC.txt added
* a2410e0 Audience.txt added
* 68a073e File2 added
* c43539f File1 added
π Observation:
- A merge commit (
ff8fcb1) is created. - The branch history is not linear due to the explicit merge commit.
| Merge Type | Pros β | Cons β |
|---|---|---|
| Fast Forward | Keeps history linear π | History may not reflect actual merging β³ |
| No Fast Forward | Creates an explicit merge commit π | More commits in history π |
π Key Takeaway:
- If you want a cleaner linear history, use Fast Forward.
- If you want to track merges explicitly, use No Fast Forward.
To ensure all merges require an explicit commit:
git config --global merge.ff noπ§ This applies to all repositories globally.
- A Fast Forward Merge keeps a linear history when branches haven't diverged.
- A No Fast Forward Merge creates a merge commit, making it easier to track changes.
- Git allows configuring
merge.ff noto enforce No Fast Forward merges.
π― Choose the strategy that best fits your team's workflow!
In this lesson, we'll explore the concept of a three-way merge in Git. This is useful when two branches have diverged, meaning they have independent changes that need to be merged back together.
First, let's check our Git history to see where we are:
$ git log --oneline --all --graphπΉ Output:
* ff8fcb1 (HEAD -> master) Merge branch 'bugfix/login-form'
|\
| * 8538e99 (bugfix/login-form) Update toc.txt
|/
* f76e273 (bugfix/signup-form) Fix the bug that protect user from sign up
* 8797d0e TOC.txt added
* a2410e0 Audience.txt added
* 68a073e File2 added
* c43539f File1 added
Let's create a new branch for implementing a Change Password feature:
$ git switch -C feature/change-passwordπΉ Output:
Switched to a new branch 'feature/change-password'
Now, let's check our history again:
$ git log --oneline --all --graphπΉ Output:
* ff8fcb1 (HEAD -> feature/change-password, master) Merge branch 'bugfix/login-form'
|\
| * 8538e99 (bugfix/login-form) Update toc.txt
|/
* f76e273 (bugfix/signup-form) Fix the bug that protect user from sign up
* 8797d0e TOC.txt added
* a2410e0 Audience.txt added
* 68a073e File2 added
* c43539f File1 added
Both master and feature/change-password are pointing to the same commit.
Let's add a new file related to the Change Password feature:
$ echo hello > change-password.txt
$ git add .
$ git commit -m "Build the change password form"πΉ Output:
[feature/change-password 6ca05c1] Build the change password form
1 file changed, 1 insertion(+)
create mode 100644 change-password.txt
Checking the history again:
$ git log --oneline --all --graphπΉ Output:
* 6ca05c1 (HEAD -> feature/change-password) Build the change password form
* ff8fcb1 (master) Merge branch 'bugfix/login-form'
|\
| * 8538e99 (bugfix/login-form) Update toc.txt
|/
* f76e273 (bugfix/signup-form) Fix the bug that protect user from sign up
Now, let's switch back to master and modify a file:
$ git switch master
$ git add toc.txt
$ git commit -m "Update TOC.txt"πΉ Output:
[master 80a74e4] Update TOC.txt
1 file changed, 1 insertion(+), 1 deletion(-)
Checking the log:
$ git log --oneline --all --graphπΉ Output:
* 80a74e4 (HEAD -> master) Update TOC.txt
| * 6ca05c1 (feature/change-password) Build the change password form
|/
* ff8fcb1 Merge branch 'bugfix/login-form'
|\
| * 8538e99 (bugfix/login-form) Update toc.txt
|/
* f76e273 (bugfix/signup-form) Fix the bug that protect user from sign up
Now, the feature/change-password and master branches have diverged.
Since both branches have independent changes, let's merge them:
$ git merge feature/change-passwordπΉ Output:
Merge made by the 'ort' strategy.
change-password.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 change-password.txt
Checking the final log:
$ git log --oneline --all --graphπΉ Output:
* e090bc9 (HEAD -> master) Merge branch 'feature/change-password'
|\
| * 6ca05c1 (feature/change-password) Build the change password form
* | 80a74e4 Update TOC.txt
|/
* ff8fcb1 Merge branch 'bugfix/login-form'
βοΈ We successfully created a feature branch, made changes to it, modified the master branch separately, and performed a three-way merge.
π‘ Key Takeaways:
- A three-way merge occurs when two branches have diverged.
- Git compares the latest commits on both branches with their common ancestor.
- The merge process creates a new merge commit that combines changes from both branches.
π Now you have a solid understanding of how to handle a three-way merge in Git! π
When we finish working on a branch, the best practice is to merge it into the master (or main) branch and then delete it. However, sometimes we forget to delete a merged branch. Over time, these branches pile up, leading to confusion about whether they are already merged or not.
Let's go through how to check for merged and unmerged branches.
Currently, we are on the master branch. To see the list of branches that have been merged into the current branch (master), use the following command:
git branch --mergedThis will display all the branches that have already been merged into master. Since these branches have been merged, it's safe to delete them if you're done working on them.
π Best practice: Delete merged branches to keep your repository clean and organized!
To delete a merged branch, use:
git branch -d bugfix/loginπΉ This will remove the bugfix/login branch since it's already merged.
To check for branches that have not been merged into the current branch, use:
git branch --no-mergedIf no output appears, it means that all branches have already been merged. If there are branches listed, it means they are still unmerged and may contain important work.
β
Use git branch --merged to list merged branches.
β
Use git branch --no-merged to list unmerged branches.
β
Delete merged branches using git branch -d <branch-name> to keep your repo clean.
By following these steps, you can efficiently manage branches in Git and avoid unnecessary clutter in your repository. πβ¨
When working with Git, merging branches is a common task. However, merge conflicts often arise when changes overlap. This guide demonstrates handling merge conflicts through a practical example.
git branchOutput:
bugfix/login-form
bugfix/signup-form
feature/change-password
* master
π The asterisk (*) indicates the active branch (master).
git switch -C bugfix/change-passwordOutput:
Switched to a new branch 'bugfix/change-password'
π This command creates (-C) and switches to the bugfix/change-password branch.
code change-password.txtπ Opens change-password.txt in VS Code for editing.
git add .
git commit -m"Update change-password.txt"Output:
[bugfix/change-password 397f30f] Update change-password.txt
1 file changed, 1 insertion(+)
π Stages all changes (git add .) and commits them with a message.
git log --oneline --all --graphOutput (Simplified):
* 397f30f (HEAD -> bugfix/change-password) Update change-password.txt
* e090bc9 (master) Merge branch 'feature/change-password'
* | 80a74e4 Update TOC.txt
π Displays a graphical representation of commit history.
git switch masterOutput:
Switched to branch 'master'
π Moves back to the master branch.
git merge bugfix/change-passwordOutput:
Auto-merging change-password.txt
CONFLICT (content): Merge conflict in change-password.txt
Automatic merge failed; fix conflicts and then commit the result.
π A merge conflict occurs because change-password.txt has different changes in both branches.
git statusOutput:
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
both modified: change-password.txt
π Git indicates that change-password.txt has conflicts.
code change-password.txtπ Opens the file in VS Code to manually resolve conflicts.
<<<<<<< HEAD
Change in the master branch
=======
Change in the bugfix branch
>>>>>>> bugfix/change-password
π Git marks conflicts with:
<<<<<<< HEAD: Changes in the current branch (master)=======: Divider>>>>>>>: Changes in the other branch (bugfix/change-password)
Change in the master branch
Change in the bugfix branchπ Manually remove conflict markers and keep both changes.
git add change-password.txt
git commitOutput:
[master 5c03854] Merge branch 'bugfix/change-password'
π The merge is now successfully completed! π
- Merge conflicts happen when the same file is modified differently in two branches.
- Git marks conflicts with
<<<<<<<,=======, and>>>>>>>. - Resolve conflicts manually, stage changes, and commit.
- Avoid introducing new code while resolving conflicts unless necessary.
When merging branches in Git, you might face merge conflicts. This happens when Git is unable to automatically reconcile differences between the branches. In such cases, Git requires you to manually resolve the conflicts before proceeding with the merge.
Sometimes, you may not have time to resolve conflicts immediately, or you may be in the middle of another task. In such situations, Git provides a way to abort the merge and return to the previous state.
To abort an ongoing merge, use the following command:
$ git merge --abort- This command cancels the merge process.
- It resets your working directory to the state before the merge started.
- If you have already resolved some conflicts and staged the changes, those changes will be discarded.
- Your repository will return to a clean state as if the merge never happened.
$ mkdir merge-example
$ cd merge-example
$ git initOutput:
Initialized empty Git repository in /path/to/merge-example/.git/
$ git checkout -b feature-branchOutput:
Switched to a new branch 'feature-branch'
echo "Hello from feature branch!" > file.txt
git add file.txt
git commit -m "Added file.txt in feature branch"Output:
[feature-branch (root-commit) 123abc] Added file.txt in feature branch
1 file changed, 1 insertion(+)
create mode 100644 file.txt
$ git checkout main
echo "Hello from main branch!" > file.txt
git add file.txt
git commit -m "Modified file.txt in main branch"Output:
[main 456def] Modified file.txt in main branch
1 file changed, 1 insertion(+), 1 deletion(-)
$ git merge feature-branchOutput (Merge Conflict Detected):
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the result.
If you're not ready to resolve the conflict, use:
$ git merge --abortOutput: (No explicit output, but the merge is aborted)
$ git statusOutput:
On branch main
nothing to commit, working tree clean
- Encountered a merge conflict? Git will notify you about it.
- Not ready to resolve? Use
git merge --abortto go back to the previous clean state. - No changes will be saved from the merge attempt if you abort it.
This technique is very useful when dealing with complex conflicts and needing to step back before making final decisions. π οΈπ₯
A merge commit is created when Git combines two branches together. However, sometimes after merging, we realize that the merge introduced issues, such as compilation errors or logical conflicts in our application. In such cases, we need to undo the merge.
There are two main ways to undo a merge:
- Resetting the commit (if the merge is local and has not been pushed to the remote repository)
- Reverting the commit (if the merge has already been pushed)
Before making any changes, let's inspect the Git commit history using:
$ git log --oneline --all --graph* 5c03854 (HEAD -> master) Merge branch 'bugfix/change-password'
|\
| * 397f30f (bugfix/change-password) Update change-password.txt
* | 8de2d9a Update change-password.txt
|/
* e090bc9 Merge branch 'feature/change-password'
|\
| * 6ca05c1 (feature/change-password) Build the change password form
* | 80a74e4 Update TOC.txt
|/
πΉ The topmost commit 5c03854 is a merge commit.
πΉ This merge combined the bugfix/change-password branch into master.
If the merge was local and has not been pushed, we can remove it completely using:
$ git reset --hard HEAD~1HEAD is now at 8de2d9a Update change-password.txt
This moves HEAD one commit back, effectively removing the merge.
π Note: --hard option resets both the working directory and index.
πΉ Let's check the history again:
$ git log --oneline --all --graph* 8de2d9a (HEAD -> master) Update change-password.txt
| * 397f30f (bugfix/change-password) Update change-password.txt
|/
* e090bc9 Merge branch 'feature/change-password'
The merge commit is no longer in the history!
If you mistakenly reset a merge, you can restore it using the commit hash:
$ git reset --hard 5c03854HEAD is now at 5c03854 Merge branch 'bugfix/change-password'
Now the merge is back! π
If the merge has been pushed to a remote repository, we should not use reset. Instead, we revert the merge to create a new commit that cancels the merge changes.
Let's try to revert the last merge commit:
$ git revert HEADerror: commit 5c03854 is a merge but no -m option was given.
fatal: revert failed
π Why did this fail? A merge commit has two parents, and Git needs to know which parent to keep.
β
To revert the merge while keeping the changes from master, we use:
$ git revert -m 1 HEAD[master 6e0b0dd] Revert "Merge branch 'bugfix/change-password'"
1 file changed, 1 insertion(+), 1 deletion(-)
πΉ -m 1 tells Git to keep the first parent (master branch) while undoing the merge.
πΉ Let's verify the new history:
$ git log --oneline --all --graph* 6e0b0dd (HEAD -> master) Revert "Merge branch 'bugfix/change-password'"
* 5c03854 Merge branch 'bugfix/change-password'
|\
| * 397f30f (bugfix/change-password) Update change-password.txt
* | 8de2d9a Update change-password.txt
|/
A new commit (6e0b0dd) has been added to undo the merge!
When we use git reset, we can specify different options to control what gets updated. These options determine how Git manipulates the HEAD, staging area, and working directory.
- The HEAD pointer moves to the specified commit.
- The staging area (index) remains unchanged.
- The working directory remains unchanged.
- Example:
This moves HEAD back by one commit but keeps the changes staged.
git reset --soft HEAD~1
- The HEAD pointer moves to the specified commit.
- The staging area is updated to match the new HEAD.
- The working directory remains unchanged.
- Example:
This resets the last commit and unstages the changes, but they remain in the working directory.
git reset --mixed HEAD~1
- The HEAD pointer moves to the specified commit.
- The staging area is updated to match the new HEAD.
- The working directory is also updated, discarding any changes.
- Example:
This removes the last commit and any local changes permanently.
git reset --hard HEAD~1
| Option | HEAD Moves | Staging Area Updates | Working Directory Updates |
|---|---|---|---|
--soft |
β | β | β |
--mixed |
β | β | β |
--hard |
β | β | β |
Be careful when using --hard as it will remove any uncommitted changes permanently!
| Command | Action |
|---|---|
git log --oneline --all --graph |
View commit history |
git reset --hard HEAD~1 |
Remove last commit (use only if not pushed) |
git reset --hard <commit-hash> |
Restore a removed commit |
git revert HEAD |
Undo last commit (fails for merge commits) |
git revert -m 1 HEAD |
Revert a merge commit and keep first parent |
π Best Practice: Use reset only for local changes. If the merge has been pushed, always use revert!
π‘ Now you know how to safely undo a Git merge! π
Squash merging is a powerful technique in Git that allows us to combine multiple commits into a single commit before merging into the main branch. This helps keep the commit history clean and avoids unnecessary, low-quality commits from cluttering the master branch.
git switch -C bugfix/photo-uploadπ Explanation:
git switch -C bugfix/photo-uploadcreates a new branch calledbugfix/photo-uploadand switches to it.-Censures that the branch is created if it doesn't exist.
echo bugfix >> audience.txt
git commit -am "Update audience.txt"Git Output:
[bugfix/photo-upload afa2081] Update audience.txt
1 file changed, 1 insertion(+)
π Explanation:
echo bugfix >> audience.txtadds a line containing "bugfix" toaudience.txt.git commit -am "Update audience.txt"stages and commits the changes with a message.
echo bugfix >> toc.txt
git commit -am "Update toc.txt"Git Output:
[bugfix/photo-upload 1c9a356] Update toc.txt
1 file changed, 1 insertion(+)
π Explanation:
echo bugfix >> toc.txtadds "bugfix" totoc.txt.git commit -am "Update toc.txt"stages and commits the change.
git log --oneline --all --graphGit Output:
* 1c9a356 (HEAD -> bugfix/photo-upload) Update toc.txt
* afa2081 Update audience.txt
* 6e0b0dd (master) Revert "Merge branch 'bugfix/change-password'"
* 5c03854 Merge branch 'bugfix/change-password'
|\
| * 397f30f (bugfix/change-password) Update change-password.txt
* | 8de2d9a Update change-password.txt
|/
* e090bc9 Merge branch 'feature/change-password'
|\
| * 6ca05c1 (feature/change-password) Build the change password form
* | 80a74e4 Update TOC.txt
|/
* ff8fcb1 Merge branch 'bugfix/login-form'
|\
| * 8538e99 (bugfix/login-form) Update toc.txt
|/
* f76e273 (bugfix/signup-form) Fix the bug that protect user from sign up
* 8797d0e TOC.txt added
* a2410e0 Audience.txt added
* 68a073e File2 added
* c43539f File1 added
π Explanation:
- This command displays the commit history in a compact format.
Instead of this kind of normal 3 way merge like this,
We do a Squash Merge.
git switch masterπ Explanation:
git switch mastermoves us back to the master branch.
git merge --squash bugfix/photo-uploadGit Output:
Updating 6e0b0dd..1c9a356
Fast-forward
Squash commit -- not updating HEAD
audience.txt | 1 +
toc.txt | 1 +
2 files changed, 2 insertions(+)
π Explanation:
git merge --squash bugfix/photo-uploadmerges all changes frombugfix/photo-uploadinto the staging area as a single commit.- No merge commit is created, ensuring a clean history.
git commit -m "Fix the bug on the photo upload page"Git Output:
[master 76a9526] Fix the bug on the photo upload page
2 files changed, 2 insertions(+)
π Explanation:
- We manually commit the squashed changes with a meaningful message.
git branch --mergedGit Output:
bugfix/change-password
bugfix/login-form
bugfix/signup-form
feature/change-password
* master
git branch --no-mergedGit Output:
bugfix/photo-upload
π Explanation:
git branch --mergedshows branches that are fully merged.git branch --no-mergedshows branches not recognized as merged (due to squash merge).
git branch -D bugfix/photo-uploadGit Output:
Deleted branch bugfix/photo-upload (was 1c9a356).
π Explanation:
git branch -Dforces deletion because Git does not recognize the branch as merged.
git log --oneline --all --graphGit Output:
* 76a9526 (HEAD -> master) Fix the bug on the photo upload page
* 6e0b0dd Revert "Merge branch 'bugfix/change-password'"
π Explanation:
- We now have a clean, linear history with a single commit representing all changes.
β Squash merging combines multiple commits into a single commit, keeping history clean. β Use squash merging for short-lived feature branches or bugfix branches. β Always delete the target branch after a squash merge to avoid confusion. β Squash merging does not create a merge commit, making the history linear. β Be cautious of conflicts, and resolve them before committing.
Squash merging is a great tool to maintain a clean and readable Git history. It helps when you have fine-grained commits that you donβt want to clutter your main branch. However, use it wisely and avoid squash merging large, complex feature branches that need to maintain detailed commit history.
Version control systems fall into two main categories:
- Centralized Version Control Systems (CVCS) β e.g., Subversion (SVN)
- Distributed Version Control Systems (DVCS) β e.g., Git
- A single repository is shared among all team members.
- Everyone is dependent on this central repository.
- Disadvantage: If the central server goes offline, no one can commit or view the project history. β
- Every developer has their own local repository.
- Developers can work offline with their local repository. β
- Collaboration happens by synchronizing changes with others.
- No single point of failure! π
However, direct synchronization between developers is complex and error-prone. Instead, we use structured workflows to collaborate efficiently.
In this workflow, we combine the best of both centralized and distributed models:
- Everyone has a local repository.
- A central repository is used to synchronize work.
- Developers push their changes to the central repository.
- Others pull the latest changes from the central repository.
π Example: John & Amy collaborate on a project:
- Cloning β They each take a copy of the central repository.
- Committing β John makes some commits locally. Meanwhile, Amy makes her own commits.
- Pushing β John pushes his changes to the central repository.
- Pulling β Amy pulls John's changes into her local repository.
- Conflict Resolution β If there are conflicts, Amy resolves them before pushing her work.
π₯ Use Case: This workflow is commonly used in private teams and closed-source projects.
β No single point of failure β work continues even if the central repository is down.
β Allows offline development.
β Can use Git hosting services like GitHub, GitLab, or an internal server.
Open-source projects require a different workflow since contributors are unknown and cannot be given direct write access. π
π Example: Contributing to an open-source project:
- Forking β Create a copy of the project repository in the cloud (e.g., on GitHub).
- Cloning β Download the forked repository locally.
- Committing β Make changes and commit them locally.
- Pushing β Push the changes to the forked repository.
- Pull Request β Submit a request to merge changes into the official repository.
- Review & Merge β Maintainers review the changes and, if approved, merge them.
π Key Aspects:
- Only maintainers have push access to the main repository.
- Contributors fork the repository and make changes in their own copy.
- Changes are proposed via pull requests.
π₯ Use Case: This workflow is widely used in open-source projects.
- Centralized Workflow: Used in private teams for easier collaboration.
- Integration Manager Workflow: Used in open-source projects to maintain security and organization.
In this notebook, we will explore the essential Git commands used to synchronize a local repository with a remote repository. We will walk through the process of fetching updates, merging branches, and understanding Git logs, along with their outputs.
git log --oneline --all --graph* e747ff8 (HEAD -> main, origin/main, origin/HEAD) Initial commit
- This command shows a compact, one-line-per-commit view of the commit history in a graphical format.
- The
HEADpointer indicates that our working branch ismain.
git fetchremote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 921 bytes | 115.00 KiB/s, done.
From https://github.com/Sithum-Bimsara/MarsSithum
e747ff8..7d3dbdd main -> origin/main
git fetchdownloads updates from the remote repository.- The commit
7d3dbddis a new update available inorigin/main, but it hasn't been merged yet.
git log --oneline --all --graph* 7d3dbdd (origin/main, origin/HEAD) Update README.md
* e747ff8 (HEAD -> main) Initial commit
- The latest commit (
7d3dbdd) exists remotely but hasn't been applied locally yet.
git branch -vv* main e747ff8 [origin/main: behind 1] Initial commit
- The local branch is behind the remote branch by one commit.
git merge origin/mainUpdating e747ff8..7d3dbdd
Fast-forward
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
- Since there are no conflicting changes, Git performs a fast-forward merge, updating
mainto the latest commit. - The README.md file has been modified with 2 insertions and 1 deletion.
git log --oneline --all --graph* 7d3dbdd (HEAD -> main, origin/main, origin/HEAD) Update README.md
* e747ff8 Initial commit
- Now,
HEADandmainare in sync withorigin/main.
git branch -vv* main 7d3dbdd [origin/main] Update README.md
- The message "behind 1 commit" is no longer displayed since our branch is up-to-date.
type README.md# MarsSithum
A new line of code
- The README file has been successfully updated with the new content.
- git log --oneline --all --graph π β View commit history.
- git fetch π β Download updates from the remote repository.
- git log --oneline --all --graph π΅οΈββοΈ β Check fetched commits.
- git branch -vv π β Verify local vs. remote branch status.
- git merge origin/main π β Merge remote changes.
- git log --oneline --all --graph β β Confirm merge success.
- git branch -vv π― β Check updated branch status.
- type README.md π β Verify file updates.
π Now, our local repository is successfully updated with the latest changes from the remote repository!
When working with Git, it's essential to keep our local repository up-to-date with the remote repository. The two primary methods to achieve this are:
- Merge - Combines remote changes with local changes using a three-way merge.
- Rebase - Reapplies local changes on top of remote changes to maintain a linear history.
To bring changes from the remote repository to our local repository, we usually:
- Fetch to download new changes.
- Merge to integrate them into our local branch.
Instead of running these separately, we can use the git pull command, which combines both operations.
Imagine we have a repository with the following commit history:
A -- (Local and Remote repositories are the same)
Then, changes happen in both repositories:
- Local Repository: Adds commit B
- Remote Repository: Adds commit C
When we run:
git pullGit will:
- Download commit C.
- Merge C into our local repository.
Since the branches have diverged, Git performs a three-way merge.
However, this creates a non-linear history. If you prefer a cleaner history, you can use rebase instead.
Rebasing changes the base of our branch from A to C and reapplies our local changes on top of C:
git pull --rebaseThis results in a linear history instead of a merge commit.
- Merge: Useful when you want to keep track of how changes evolved.
- Rebase: Keeps history cleaner but rewrites commit history.
- Best Practice: Use rebase for private branches and merge for public/shared branches.
- Edit a file (e.g.,
README.md) on GitHub. - Add a new commit:
Commit C.
touch file1.txt
git add file1.txt
git commit -m "Add file1"Now, our local and remote branches have diverged.
git log --oneline --all --graphπΉ Output:
* 707183c (HEAD -> main) Added file1
* 7d3dbdd (origin/main, origin/HEAD) Update README.md
* e747ff8 Initial commit
git pullThis performs a three-way merge, resulting in a merge commit:
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 935 bytes | 17.00 KiB/s, done.
From https://github.com/Sithum-Bimsara/MarsSithum
7d3dbdd..d64938f main -> origin/main
Merge made by the 'ort' strategy.
README.md | 1 +
1 file changed, 1 insertion(+)
git log --oneline --all --graphπΉ Output:
* 2d9bc47 (HEAD -> main) Merge branch 'main' of https://github.com/Sithum-Bimsara/MarsSithum
|\
| * d64938f (origin/main, origin/HEAD) Update README.md
* | 707183c Added file1
|/
* 7d3dbdd Update README.md
* e747ff8 Initial commit
git reset --hard HEAD~1Now our branch is back to the state before merging.
git log --oneline --all --graphπΉ Output:
* 707183c (HEAD -> main) Added file1
| * d64938f (origin/main, origin/HEAD) Update README.md
|/
* 7d3dbdd Update README.md
* e747ff8 Initial commit
git pull --rebaseThis replays our local changes on top of the latest remote commit, resulting in a linear history.
git log --oneline --all --graphπΉ Output:
* c529db5 (HEAD -> main) Added file1
* d64938f (origin/main, origin/HEAD) Update README.md
* 7d3dbdd Update README.md
* e747ff8 Initial commit
Now we have a linear history instead of a merge commit.
Once our local repository is ahead of the remote, we push changes using:
git pushThis sends new commits to the remote repository.
If someone else has pushed new commits before us, our push may be rejected. In this case:
git pull --rebaseResolve conflicts if any, then push again:
git pushForcing a push (git push --force) can overwrite other people's work. Avoid using it unless you are sure.
git pull=git fetch+git mergegit pull --rebasereplays local commits on top of remote commits for a linear history.git pushsends local commits to the remote repository.- Always pull and resolve conflicts before pushing.
π Follow these best practices for a smooth Git workflow! π
In our local repository, our master branch is ahead of origin/master by one commit. This means we have made a change locally that is not yet in the remote repository. To sync our local changes with the remote repository, we use the git push command.
- Git sends our new commit to the remote repository.
- The
masterpointer moves forward to point to the new commit. - The
origin/masterpointer also updates to reflect the new commit.
$ git push- Here,
git pushis enough because Git assumesoriginas the default remote repository. - If needed, you can specify explicitly:
$ git push origin master
π‘ Note: If authentication is required, Git will prompt you to enter your GitHub credentials (email and password).
Once the push is successful, we can verify it on GitHub:
- Navigate to the repository on GitHub.
- Check the commits section.
- You should see the latest commit listed.
Sometimes, when you try to push, Git rejects your changes. This happens when someone else has pushed new commits to the remote repository before you.
$ git push --force- This force-push will override other peopleβs work, which is highly discouraged unless necessary.
- Only use this if you fully understand the consequences.
To safely merge new changes before pushing:
-
Fetch the latest changes from remote:
$ git pull --rebase
- This pulls the new commits and places your changes on top.
- If there are conflicts, resolve them manually.
-
Merge or Rebase if Needed
$ git merge origin/master
or
$ git rebase origin/master
-
Push Again
$ git push
Looking at the commit history, letβs analyze what changes exist in our local repository that are missing in the remote repository.
- Local repository: Commits A, B, C, D, and M
- Remote repository: Commits A, B, and D
- Missing commits in remote: C and M
When we do git push, Git will send C and M to the remote repository, ensuring both repositories are now in sync.
- Use
git pushto upload commits. - If a push is rejected, first pull and merge.
- Never use
--forceunless absolutely necessary! - Keep your repository history clean and conflict-free.
Git tags are useful for marking specific points in the repository's history, such as version releases. By default, tags are not pushed to remote repositories, so they must be explicitly pushed. This notebook walks through the process of creating, pushing, deleting, and verifying tags in Git.
To create a new tag, we use the git tag command followed by the desired tag name:
C:\Users\User\Desktop\New folder\MarsSithum>git tag v1.0This adds a tag v1.0 to the most recent commit.
To check the created tag, we use:
C:\Users\User\Desktop\New folder\MarsSithum>git log --onelineOutput:
c529db5 (HEAD -> main, tag: v1.0, origin/main, origin/HEAD) Added file1
d64938f Update README.md
7d3dbdd Update README.md
e747ff8 Initial commitThe (tag: v1.0) confirms that the tag v1.0 has been added.
Since tags are not pushed by default, we explicitly push them:
C:\Users\User\Desktop\New folder\MarsSithum>git push origin v1.0Output:
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/Sithum-Bimsara/MarsSithum.git
* [new tag] v1.0 -> v1.0Now the tag v1.0 is available on GitHub.
If a tag is pushed by accident, it can be removed from the remote repository:
C:\Users\User\Desktop\New folder\MarsSithum>git push origin --delete v1.0Output:
To https://github.com/Sithum-Bimsara/MarsSithum.git
- [deleted] v1.0The tag is now deleted from the remote repository.
We can push the tag again if needed:
C:\Users\User\Desktop\New folder\MarsSithum>git push origin v1.0Output:
Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To https://github.com/Sithum-Bimsara/MarsSithum.git
* [new tag] v1.0 -> v1.0The tag is once again available on GitHub.
If we try to create a tag that already exists, Git returns an error:
C:\Users\User\Desktop\New folder\MarsSithum>git tag v1.0Error Output:
fatal: tag 'v1.0' already existsTo delete the local tag before recreating it:
git tag -d v1.0- Tags help mark specific versions of a project.
- They are not pushed automatically and must be explicitly pushed.
- Tags can be deleted from remote using
git push origin --delete <tag>. - Local tags remain unless deleted manually using
git tag -d <tag>.
These operations ensure better version control and collaboration in Git projects. π
In this notebook, we will explore how to work with Git branches, push them to a remote repository, set upstream branches, and delete them. We will also discuss how remote tracking branches work.
git switch -C feature/change-passwordOutput:
Switched to a new branch 'feature/change-password'
β
This command creates a new branch named feature/change-password and switches to it.
git pushOutput:
fatal: The current branch feature/change-password has no upstream branch.
β The branch does not have an upstream branch on the remote repository.
To link it with the remote repository, use:
git push --set-upstream origin feature/change-passwordTo check local and remote tracking branches, use:
git branch -vvOutput:
* feature/change-password c529db5 Added file1
main c529db5 [origin/main] Added file1
To see remote tracking branches:
git branch -rOutput:
origin/HEAD -> origin/main
origin/main
π The remote repository currently tracks only the main branch.
git push -u origin feature/change-passwordOutput:
To https://github.com/Sithum-Bimsara/MarsSithum.git
* [new branch] feature/change-password -> feature/change-password
branch 'feature/change-password' set up to track 'origin/feature/change-password'.
β
Now, the local branch feature/change-password is linked to the remote branch.
Verify by running:
git branch -vvOutput:
* feature/change-password c529db5 [origin/feature/change-password] Added file1
main c529db5 [origin/main] Added file1
π The branch is now tracked remotely.
Check remote branches again:
git branch -rOutput:
origin/HEAD -> origin/main
origin/feature/change-password
origin/main
π Now, feature/change-password exists on GitHub.
To delete the remote branch:
git push -d origin feature/change-passwordOutput:
To https://github.com/Sithum-Bimsara/MarsSithum.git
- [deleted] feature/change-password
β The branch is removed from the remote repository.
Check remote branches:
git branch -rOutput:
origin/HEAD -> origin/main
origin/main
π The feature/change-password branch no longer exists on the remote repository.
Check local branches:
git branch -vvOutput:
* feature/change-password c529db5 [origin/feature/change-password: gone] Added file1
main c529db5 [origin/main] Added file1
π The local branch still exists, but its remote tracking branch is marked as gone.
To switch to the main branch:
git switch mainOutput:
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
β
We are now back on the main branch.
- Created a new branch
feature/change-password. - Pushed the branch to the remote repository and linked it.
- Checked local and remote tracking branches.
- Deleted the branch from the remote repository.
- Switched back to the
mainbranch.
π This is how you create, push, track, and delete branches in Git!
Imagine Amy and I are collaborating on a feature together. There are two ways to create a feature branch:
- Create a feature branch locally and push it to GitHub.
- Create a branch directly on GitHub. (We'll use this method.)
- Navigate to the branch dropdown in GitHub.
- Create a new branch called
feature/change-password. - This branch is currently even with
master. - As we push changes, we can track how far ahead this branch is compared to
master.
$ git fetchFetching origin
* [new branch] feature/change-password -> origin/feature/change-password
- A new remote tracking branch
origin/feature/change-passwordis fetched. - We also see a new tag created earlier.
$ git branch* master
β Where is the new branch?
- It exists remotely but not locally yet!
$ git branch -rorigin/feature/change-password
origin/master
$ git switch -C feature/change-password origin/feature/change-passwordSwitched to a new branch 'feature/change-password'
Branch 'feature/change-password' set up to track remote branch 'feature/change-password' from 'origin'.
- Now, our local branch is tracking the remote branch!
Amy starts by cloning the repository:
$ git clone <repository_url>She navigates to the project directory:
$ cd project-directoryChecking available branches:
$ git branch* master
β The feature/change-password branch isn't here yet!
Amy creates a local branch tracking the remote one:
$ git switch -C feature/change-password origin/feature/change-passwordSwitched to a new branch 'feature/change-password'
Branch 'feature/change-password' set up to track remote branch 'feature/change-password' from 'origin'.
$ echo "password" > file1.txt
$ git add file1.txt
$ git commit -m "Update file1.txt"
$ git push[feature/change-password abc1234] Update file1.txt
1 file changed, 1 insertion(+)
create mode 100644 file1.txt
...
- The commit appears on GitHub.
Checking GitHub repository:
- GitHub UI shows: "feature/change-password had recent pushes 1 minute ago."
- Commits page now has 4 commits.
I pull Amy's changes:
$ git pullFast-forward
file1.txt | 1 +
1 file changed, 1 insertion(+)
I check the log:
$ git log --oneline --all --graphfeature/change-passwordis ahead ofmasterby 1 commit.
I switch to master and merge the feature branch:
$ git switch master
$ git merge feature/change-passwordFast-forward
file1.txt | 1 +
1 file changed, 1 insertion(+)
Pushing the final changes to GitHub:
$ git push$ git push -d origin feature/change-passwordTo <repository_url>
- [deleted] feature/change-password
$ git branch -d feature/change-passwordDeleted branch feature/change-password.
$ git remote prune originPruning origin
URL: <repository_url>
* [pruned] origin/feature/change-password
Checking branches:
$ git branch* master
Checking remote tracking branches:
$ git branch -rorigin/master
β Feature branch is completely removed from local and remote repositories.
This walkthrough demonstrates a real-world collaboration scenario in Git:
- Creating and switching to feature branches.
- Pushing and pulling changes collaboratively.
- Merging features into the master branch.
- Cleaning up unused branches after merging.
Now, we can apply these concepts in a team workflow efficiently! π
Milestones help us track the progress of various issues in a project. We can add multiple issues to a milestone and monitor our progress towards completing that milestone.
- Navigate to the Issues tab.
- Click on Milestones.
- Click on New Milestone.
- Provide a title (e.g.,
Version 2.0.0). - Optionally, set a due date (e.g.,
January 13, 2025). - Add a description (optional but recommended).
- Click Create Milestone.
β Now, we have a milestone created! It will appear in the Milestones tab.
- Go to the Issues page.
- Select an issue (or multiple issues).
- Assign them to the milestone we created (
Version 2.0.0).
π Checking the Milestone Progress:
- Go back to the Milestones tab.
- We can now see the number of open and closed issues.
- The completion percentage is displayed (e.g.,
0% completeif no issues are closed).
- Navigate to the Issues tab.
- Select the assigned issue.
- Click Close issue.
π Refreshing the Milestones Page:
- The milestone progress updates.
- If all issues are closed, the milestone is marked complete! π
# Viewing milestones
$ gh issue list --milestone "Version 2.0.0"
# Output Example
# No issues assigned yet# Assigning an issue to the milestone
$ gh issue edit 1 --milestone "Version 2.0.0"
# Output Example
Issue #1 has been added to milestone "Version 2.0.0"# Closing an issue
$ gh issue close 1
# Output Example
Issue #1 is now closed.# Checking milestone progress
$ gh milestone view "Version 2.0.0"
# Output Example
Title: Version 2.0.0
Due Date: September 30, 2020
Open Issues: 0
Closed Issues: 1
Completion: 100%- Milestones help us track progress efficiently.
- Issues can be assigned to milestones.
- Closing issues updates milestone progress.
- Once all issues are closed, the milestone is complete.






































