0% found this document useful (0 votes)
14 views83 pages

Manu V - I15600: A Leading Provider of Smart, Connected and Secure Embedded Control Solutions

The document provides an overview of Git, focusing on its repository types, commands for managing files, branches, and merging processes. It explains local and remote repositories, the use of commands like git init, git clone, git add, git commit, and the concept of branches and merges. Additionally, it covers the push and pull request processes for collaboration in Git-based platforms.

Uploaded by

shilps1234abc
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
14 views83 pages

Manu V - I15600: A Leading Provider of Smart, Connected and Secure Embedded Control Solutions

The document provides an overview of Git, focusing on its repository types, commands for managing files, branches, and merging processes. It explains local and remote repositories, the use of commands like git init, git clone, git add, git commit, and the concept of branches and merges. Additionally, it covers the push and pull request processes for collaboration in Git-based platforms.

Uploaded by

shilps1234abc
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 83

Git

A Leading Provider of Smart, Connected and Secure Embedded Control Solutions

Manu V– I15600
Repositories
Repositories
• Repositories (or "repos") are used to manage and store project files and
their history. There are two main types of repositories:
• Local repo
• Remote repo
Local Repositories
• A local repository is stored on your computer. It's where you make changes
to files, commit those changes, and keep track of the project’s history
locally.
• You can use Git commands (like git add, git commit, etc.) to manage
changes in your local repository.
• It resides in a folder that contains a .git directory, which stores the entire
history of your project.

Working
Stage Local repository
directory
Remote Repositories
• A remote repository is a version of your project that is hosted on a remote
server (e.g., GitHub, GitLab, Bitbucket). It allows collaboration between
multiple users by syncing changes between local and remote repositories.
• Once your local repository is set up, you can link it to a remote repository
and push changes from your local repo to the remote repo, and pull
changes from the remote repo to your local system.
HEAD
• HEAD is a pointer that always points to the latest commit.
A
Head points to MAIN
before any commit

Head points to first


commit B

A B
A B C
Head points to
second commit C

• HEAD always points to latest commit of a branch by default. However, the HEAD could be
detached by checking out using particular commit hash.
Init, clone
Git init
• The git init command is used to create a new local Git repository. This command initializes
a new Git repository in the directory where it's run, making it ready to track changes in the
project's files.
cd /path/to/your/project
git init
• A hidden .git directory is created in your project folder.
• This .git folder contains all the necessary metadata for Git to track changes, manage
branches, and keep a history of your commits.
• The directory now becomes a Git repository, but it won't track files yet until you add and
commit them.
• Git init is used at the start new project and turn the project into repo
• To connect the repo to remote use,
git remote add origin <remote_repository_url>
• Origin could be linked to remote repo using
git branch --set-upstream-to=origin/main main
Git clone
• The git clone command is used to create a copy (not a branch) of an
existing Git repository from a remote server (like GitHub, GitLab, or
Bitbucket) or from another location on your local machine.
• It copies all the files, history, branches, and commits from the remote
repository into a new directory on your local machine.
• The new directory will also be linked to the original remote repository, so
you can later sync changes using git push and git pull.
git clone https://github.com/username/repo.git
• Once a copy is made into the local machine, you can make changes to files,
commit the changes and later you can sync with the remote.
• A single branch could be cloned as
git clone --branch <branch_name> --single-branch <repository_url>
Stage, Unstage and Commit
Add and staging
• add command adds file changes to the staging area. Files in the staging area are prepared for the next
commit but are not yet committed to the repository. Essentially, you're telling Git which changes you want
to include in your next commit. Note that git only tracks files inside folders but not empty folders.
git add <file> # Add a specific file
git add . # Add all changes in the current directory and subdirectory
git add *.txt # Add all files with a specific pattern (e.g., .txt files)
git add --all # Add all changes from current working path
git add -p <file> # stage only certain parts of file
• After using git add, the changes are staged and ready to be committed.
• Staging refers to the process of preparing changes (modified or newly added files) to be included in the next
commit. The staging area is a space where you mark which changes will be included in the next commit. It
allows you to control what gets committed, so you can select specific files or portions of files to be included.
• You can unstage a file by removing the file from staged space but keep the changes in the working directory.
git restore --staged <file> # unstage <file>
git reset # unstage all changes. Resets the index
(staging area) to match previous
commit
Commit
• The git commit command saves the staged changes as a commit in the Git history. A commit represents a snapshot of the project at
a specific point in time, along with a message describing the changes.
git commit -m "Commit message here“
• The staged changes are saved as a new commit in the Git history.
• Git will now track these changes, and you can push the commit to a remote repository (e.g., GitHub) using git push.
• The previous commit could be amended (for e.g. change the commit message) by using below command.
git commit --amend -m "Updated commit message“
• If you want to undo the last commit or last few commits, then reset command is used.
git reset --soft HEAD~1 # undo last commit but keep the changes staged
git reset --soft HEAD~3 # undo last 3 commits
git reset --mixed HEAD~1 # undo last commit and unstage the changes. Changes will be in working directory
git reset --hard HEAD~1 # undo last commit and discard any changes in the working directory as
well. Resets the working directory to previous commit. Files added during previous commit will be deleted from
working directory
git reset --hard <commit hash> # resets to commit hash
• To see the commit history, use:
git log
• To see the commit history, one in each line use:
git log –oneline
• To see commit history of a directory:
git log -- <directory>
Status, Origin, difference and remove
Status
• The git status command in Git provides an
overview of the current state of your working
directory and staging area. It helps you see
which files have been modified, added, or
deleted, and which changes are staged for
the next commit or are yet to be staged.
• Status shows info of 3 types:
• Changes to be committed (staged changes): These are
files that have been staged using git add. They are ready
to be committed in your next git commit.
• Changes not staged for commit (modified but not
staged): These are files that have been changed but
haven’t been added to the staging area yet. You’ll need
to use git add to stage them.
• Untracked files: Files that are in your working directory
but haven’t been tracked by Git yet (i.e., they are new
files and haven't been added to the repository). You can
add them using git add.
Origin
• origin is the default name given to the remote repository from which you cloned your project or to which your local
repository is connected.
• When you clone a repository, Git automatically sets origin as the default alias for the URL of the remote repository.
git push origin or git pull origin use this alias to communicate with the remote repository.
• You can see the URL associated with origin using the following command:
git remote –v
• Output would be
origin https://github.com/username/repo.git (fetch)
origin https://github.com/username/repo.git (push)
• You can push the changes to remote using
git push origin <branch-name>
• You can pull the copy from remote using
git pull origin <branch-name>
• If you have a local repository and want to link it to a remote repository (e.g., GitHub), you can manually add a remote
called origin:
git remote add origin https://github.com/username/repo.git
• If the URL for your remote repository changes (for example, you change the project name), you can update origin:
git remote set-url origin https://new-url.com/username/repo.git
DIFF
• The basic git diff command shows the differences between your working directory (the files
you’ve changed) and the staging area (the files you’ve staged using git add).
git diff
• To see the differences between what’s in the staging area (files added with git add) and the last
commit, you can use the --staged flag.
git diff--staged
• To see the differences between a specific commit and your working directory (uncommitted
changes), use:
git diff <commit>
E.g. git diff HEAD # show the changes between the latest
commit (HEAD)
and the current working directory.
Remove files/directory
• One way is to delete a file/directory from working directory, then stage it and then commit it to
the local repository. These multiple steps could be avoided using rm instruction.
• To remove a file from both the working directory and the staging area (the index), use:
git rm <file> # delete <file> and stage it for next commit
• If you want to stop tracking a file in Git but keep it in your working directory, use the --cached
option:
git rm --cached <file> # delete <file> from local repository but keep it in
working directory
• Sometimes, a file might be modified in your working directory and Git won't remove it because
it contains uncommitted changes. In such cases, you can force the removal using the -f (force)
flag:
git rm -f <file>
• To remove a directory and all its files, you can use the recursive option (-r):
git rm -r <directory> # remove <directory> from both the working
directory and the local repository
Branch
Branch
• Branches allow you to work on different parts of a project independently.
• To see a list of all branches in your repository and to verify which branch you’re on, use:
git branch
Output:
* feature-branch
main # The asterisk (*) indicates the branch you are
currently working on.

• To create a new branch in Git, you use


git branch <branch-name>
• After creating the branch, you need to switch to it. To switch branches, use the git checkout
command
git checkout <branch-name>
• To list of branches along with their upstream tracking branch
git branch -vv
Branch (Contd)
• Both the steps of creating and switching could be combined using:
git checkout -b <branch-name>
• After switching to the branch, you can work on the branch by modifying the files. The files needs to staged and
committed to local repo. The branch could be merged with the parent branch.
• To push the local branch to the remote repository, use the git push command with the -u (or --set-upstream) option.
This sets the upstream branch for the local branch, so future git push and git pull commands will know which remote
branch to interact with.
git push -u origin <branch_name>
• To verify that the branch has been pushed to the remote repository, you can list the branches on the remote
repository.
git branch -r
• After merging, you might want to delete the branch if it's no longer needed. To delete a branch locally, first switch to
main branch:
git checkout main
git branch -d <branch-name>
• If you also want to delete the branch from the remote repository:
git push origin --delete <branch-name>
Branch (Contd)
• Renaming a branch
git branch -m <old_name> <new_name>
Merge
Merge
• Merging is the process of combining the changes from one branch into
another. Typically, it’s used to integrate changes from a feature branch back
into the main branch (e.g., main or master) or another branch you're
working on.
• First, ensure you're on the branch where you want to integrate the changes
(target branch). For example, if you’re merging feature-branch into main,
switch to main:
git checkout main
• Now, merge the source branch (e.g., feature-branch) into the current
branch:
git merge <branch-name> # e.g. git merge feature-
branch
Fast-forward Merge (Contd)
• A fast-forward merge in Git happens
when there is no divergence between
Main A B C
the branches you're merging.
• In the example shown, at commit C,
feature-branch is branched out from Feature-branch D E
main. However, after C, there are no
changes in main branch. So, when you
use:
git checkout main Main
A B C D E
git merge feature-branch
• In this case, feature-branch is merged
into main. Since there are no changes
since commit C in main, the head
pointer is adjusted to point commit E.
Three-way Merge (Contd)
• A three-way merge in Git is a method of merging two
branches that have diverged, meaning both branches have
Main A B C
made independent changes since their common ancestor.
Git uses three snapshots to perform the merge: the
common ancestor of both branches, the tip of the current
branch, and the tip of the branch you're merging into it.
• There are 2 ways git handles merge: Feature-branch D E
• If the changes are made by both the branches at
different parts of the file, then git includes all the
changes and commits in the target branch.
• If the changes are made differently by both the branches
Main A B C F
to the same part of the file, then there is merge conflict
in which case user has to resolve it. Git will mark the
conflict areas in the file, using markers like <<<<<<<,
=======, and >>>>>>> to show what’s different.
• As shown in the fig., feature-branch was branched out from
Feature-branch D E
commit B of main. After that main has commit C while
feature-branch had commit E. Assuming changes were to
different parts of the same file, both the changes from the
tip of both the branches (C and E) would be included and
committed to tip of main. This becomes the new commit F.
Push and Pull
Push
• Push is the command used to send your local commits to a remote repository (like
GitHub, GitLab, Bitbucket, etc.).
git push origin <branch-name>
• If you want to push all your local branches to the remote repository:
git push --all origin
• If you want to make the local branch track the remote branch automatically, you can
use this option:
git push --set-upstream origin feature-branch
• After doing this, you won’t need to specify the branch name in future git push
commands. Git will know that your local feature-branch corresponds to the remote
feature-branch.
• If you want to ignore errors during push and want to force the changes or if you have
reset your repo to older commit, then you can use:
git push --force
Pull request
• Pull Request is a request for collaboration. It is the opposite of
push. It is used to fetch and merge changes from a remote
repository into your local repository. The pull command retrieves
any changes that others have made and merges them into your
local branch.
• It is a feature typically used in Git-based platforms like GitHub,
GitLab, or Bitbucket. It is a mechanism for developers to notify
others about changes they’ve made and request that their
changes be merged into the main or other branches.
Pull request – Developer’s view
• Let’s assume you are working on a project with your team, and you want to add a new feature to the codebase.
• Step 1: Clone the remote repo
git clone <remote repo>
• Step 2: You don’t want to make changes directly in the main branch. Instead, you create a new feature branch where you will work on the new
feature.
cd repository-name
git checkout -b feature/new-feature
• Step 3: Make changes to the new branch. Add and commit the changes
git add .
git commit -m “message”
• Step 4: Push the changes to remote repo
git push origin feature/new-feature
• Step 5: Open the pull request in remote repository such as bitbucket. Click on the Compare & pull request. You will be taken to the New Pull
Request page. Add a descriptive title and description for the pull request, explaining what changes you made and why. Click on Create Pull Request
• Step 6: Once the pull request is created, your team members will be notified. They can review the changes, leave comments, or request
modifications.
• Step 7: If reviewers request changes, you can make additional commits to your feature branch. After making changes, push them to the same
branch.
• Step 8: Once the pull request is approved by the reviewers, you or a project maintainer can merge it into the main branch. In the pull request on
GitHub, click Merge pull request.
• Step 9: Once the pull request is merged into main, you should update your local main branch to keep it in sync with the remote repository:
git checkout main
git pull origin main
Stash
Stash
• Stash is a feature used to temporarily save changes in your working directory that you are not yet ready to commit. This is
useful when you want to switch branches or perform other tasks without committing incomplete work. Git saves them in a
stack of unfinished changes without committing them to the current branch. You can later apply the stashed changes back to
any branch.
• To save the uncommitted changes:
git stash save "message describing changes“
• To see a list of all the stashes you’ve saved, use:
git stash list
Output: stash@{0}: WIP on feature-branch: c0f1c3a Add new feature
stash@{1}: WIP on main: 7d6a9d0 Fix issue with header
• To apply a specific stash without removing it from the stash list, use:
git stash apply stash@{0}:
• If you want to apply the last stash and remove it from the stash list, use below. It will apply stash@{1} and removes it from list.
git stash pop
• If you no longer need a stash and want to remove it, you can drop it:
git stash drop stash@{0}
• If you want to remove all stashes from the list
git stash clear
• By default, stash is done on tracked files (files committed to branch). However, you can stash untracked files using:
git stash -u
Stash – Use case
• You’re working on a new feature in a branch (feature-branch), but you need to
switch to main branch to fix a bug, and you don’t want to commit incomplete
changes.
git stash save “incomplete test”
• Now, you can switch to main branch:
git checkout main
• Fix the bug in the main branch, commit the fix, and push it
git commit -m "Fixed bug in header“
git push origin main
• After fixing the bug, you can switch back to your feature-branch and apply your
stashed changes:
git checkout feature-branch
git stash pop
Stash – Applying changes and merge conflicts
• You modify file1.txt and stash those changes. Later,
you edit file1.txt again (without applying the stash
first) and commit the file. When you apply the stash,
Git detects that both the stash and your local repo
have changes to the same file, potentially to the same
lines, leading to a conflict.
• When a conflict occurs while applying a stash, Git will
pause the stash application and notify you of the
conflict, just like during a regular merge conflict.
• You need to manually resolve the conflict. Open the
conflicting files, and you’ll see conflict markers
(<<<<<<<, =======, >>>>>>>). These markers indicate
where the conflicts are. You need to choose between:
• Keeping the changes from the stash.
• Keeping the changes from the working directory.
• Or combining both.
• Once the conflict is resolved, save the file. Add the file.
• After this, you can try applying the stash again.
Rebase
Rebase
• Rebase is a way to apply your branch's commits on top of another
branch’s history. When you rebase, Git essentially takes all the
commits from your current branch, temporarily removes them,
applies the commits from the branch you're rebasing onto, and then
applies your removed commits on top of that. Main A B C
• No commit is created when you rebase unlike merging branches.
• Rebase creates a clean linear history. It replays your branch's
commits on top of another branch, essentially "moving" your
branch's starting point, creating a linear commit history.
• You need to checkout the branch.
git checkout feature-branch
Feature-branch D E
• Before rebasing, make sure you have the latest changes from the
main branch.
git pull
• You can now rebase your branch onto the latest main branch.
git rebase main
• This will temporarily remove your feature branch's commits. Apply
Feature branch
A B C D E
the latest changes from main to your branch. Reapply your commits
on top of the main branch.
• If there are any conflicts, then they need to be resolved manually.
Once done, the rebase could be continued
git rebase --continue
Rebase vs merge
• As you can see, I split off my feature branch at commit 2,
and have done a bit of work.
• If I run a merge, git will stuff all of my changes from my
feature branch into one large merge commit that contains
ALL of my feature branch changes. It will then place this
special merge commit onto master. When this happens, the
tree will show your feature branch, as well as the master
branch. Going further, if you imagine working on a team
with other developers, your git tree can become complex:
displaying everybody else’s branches and merges.
• let’s take a look at how rebase would handle this same
situation. What rebase will do is take all of the commits on
your feature branch and move them on top of the master
commits. Behind the scenes, git is actually blowing away the
feature branch commits and duplicating them as new
commits on top of the master branch. What you get with
this approach is a nice clean tree with all your commits laid
out nicely in a row, like a timeline. Easy to trace.
Rebase process
• Step 1: Before doing rebase make sure to pull the remote master onto local master so that they are upToDate.
git pull
• Step 2: Check out a new branch so I can write and commit code to this branch – keeping my work separated from the master branch
git checkout -b my_cool_feature
• After developing the feature, they are committed to branch
git add .
git commit -m 'This is a new commit, yay!’
• Step 3: Now that I’m done developing my feature, I want to merge my changes back into remote master. To begin this process I’ll switch back to local
master branch and pull the latest changes. This ensures my local machine has any new commits submitted by my teammates.
git checkout master
git pull
• Step 4: I’ll checkout my feature branch and rebase against my local master. This will re-anchor my branch against the latest changes I just pulled from
remote master. Additionally at this point, Git will let me know if I have any conflicts and I can take care of them on my branch.
git checkout my_cool_feature
git rebase master
• Step 5: If my feature branch doesn’t have any conflicts, I can switch back to my master branch and place my changes onto master.
git checkout master
git rebase my_cool_feature
• Since I synced with remote master before doing the rebase, I should be able to push my changes up to remote master without issues.
git push
Rebase process
Pull Pull
my_cool_feature

Remote branch Local master Remote branch


Local master
Step 1
Step 2

New feature by
co-developers

Pull Rebase local


my_cool_feature master my_cool_feature

Remote branch Remote branch


Local master Local master
Step 3 Step 4
Rebase process

Rebase branch
my_cool_feature Push

Remote branch
Local master
Remote branch Local master
Step 5
Step 6
Repo vs branch, deletion
Repository vs branch
• Repository
• A repository contains all the commits, branches, tags, and other metadata related to
the project.
• Complete history: It stores the entire history of the project—every change made, every commit, and every
branch.
• Version control: Tracks changes to files over time, allowing you to revert to earlier versions or track how the
project has evolved.
• A repository is a permanent structure
• Branch
• A branch is a parallel version of the repository that diverges from the main project. It
allows developers to work on different features, bug fixes, or experiments in isolation
without affecting the main codebase.
• A branch is a temporary structure.
Delete repo and branch
• Repository
• To delete the remote repo
• Log in to Bitbucket and navigate to the repository.
• Go to repository settings:
• On the repository’s main page, click the "Repository settings" in the left sidebar.
• Click on “Manage Repository on the right corner”
• Click on delete option and enter the repo name
• To delete the local repo
• You can remove the link to remote using:
git remote remove origin
• It’s a normal delete option
• Branch
• To delete a branch locally, first switch to main branch:
git checkout main
git branch -d <branch-name>
• If you also want to delete the branch from the remote repository:
git push origin --delete <branch-name>
Tag
Tag
• Tagging is a way to mark specific points in your repository's history as being important. Unlike
branches, which can continue moving as you add new commits, tags are static and fixed to a
particular commit.
• Tag is created as:
git tag -a <tagname> -m "Message describing the tag“
• To see the list of all tags in the repository, use:
git tag
• By default, when you push to a remote, tags are not included. To push tags to the remote, use:
git push origin <tagname>
• Just pushing tags won't have any impact on remote branch unless you push into origin
• To delete a tag locally:
git tag -d <tagname>
• To delete a tag from the remote, first delete it locally and then push the deletion to the remote.
git push origin :refs/tags/<tagname>
Tag
• To check out a specific tag, use the git checkout command followed by the tag name. For
example, if the tag you want to check out is v1.0.0, you would use:
git checkout tags/v1.0.0
Submodules
• Submodule allow you to include and track another Git repository inside your own project as a subdirectory. This is useful when you
want to include a project as a dependency but don't want to copy or integrate its code into your own repository. Instead, you can
track the external project as a separate entity while maintaining a connection to its original repository.
• Properties
• acts as a pointer to a specific commit in an external repository.
• Main repository includes the submodules
• Submodule is checked out at a specific commit rather than the repository itself
• To add a submodule to your project from already existing repositories in github etc, use
git clone <repository-url> # creates a local master
git submodule add <repository-url> <subdirectory>
• <repository-url>: The URL of the external repository you want to add as a submodule.
• <subdirectory>: The directory in your project where the submodule will be placed.
git submodule add https://github.com/example/dependency.git external/dependency
• This adds the dependency.git repository as a submodule in the external/dependency directory of your project.
• Once you create submodule and check the status of master, you will a new file .gitmodules. This is indication of successful creation
of submodule.
• Once done, you can add and commit the local master to save the changes.
• From the local master, any change made to the submodule will not have any impact on the submodule stored in the remote. Lets
say you add a file to master and submodule, commit the changes and the entire local master is pushed into remote. You will see that
all the changes made to master will only get pushed while the changes made to submodule are not. This is because submodule is
detached from the remote. You have to push the submodule explicitly although it lives with local master.
Cloning and updating repository with Submodules
• General process to clone a repo is to use.
git clone <repository-url>
• If the same code is used for a repo with submodules, this will only clone the master while the submodules directory will remain empty. To clone the repository and
initialize submodules
git clone <repository-url>
cd <repository-directory>
git submodule init
git submodule update
• If there are updates in the external repository that the submodule is pointing to, you can fetch and update them in your project.
git submodule update --remote <submodule-directory>
• When you update a submodule (either by checking out a different commit or by pulling updates from the remote), you need to commit the change to the main
repository. Git will record which commit the submodule points to.
git add <submodule-directory>
git commit -m "Updated submodule to latest commit"
• You can list all the submodules of master using:
git submodule
• To check the status of your submodules (whether they’re up to date or not), use
git submodule status
• Removing a submodule is a bit more involved than adding it. Here's the process:
git rm <submodule-directory> # Remove the submodule entry from .gitmodules
rm -rf <submodule-directory> # Remove the submodule's directory and cache:
git rm --cached <submodule-directory>
git commit -m "Removed submodule"
Pros and cons of submodules
Pros Cons
• Each submodule maintains its • By default, submodules are in a
own Git history and versioning, detached HEAD state, which means you
must manually check out branches if
making it easier to manage you want to work on the submodule
updates and changes from itself.
external projects. • If the external repository changes
• Git submodules allow you to lock frequently, you have to manually
a project to a specific commit update the submodule and commit the
change to the main repository.
from the external repository. This • Submodules add some complexity to
ensures that everyone working your workflow, especially when
on the project uses the same cloning, updating, or syncing
version of the submodule. repositories.
Subtree
• Git subtree is a way to manage sub-projects inside a Git repository. It allows you to include the contents
of another repository (called a subtree) as a subdirectory in your main repository.
• When to Use Subtree
• You want to integrate another repository into yours, but you don’t want to maintain a separate .git
directory for that repository (like with submodules).
• You want the external repository's files to be fully contained within your main repository, allowing you
to work with it as if it was part of your own project.
• You want to pull in updates from the external project, or push your changes back to it, while keeping
all your history intact.
• To add a repository as a subtree to your project, use the git subtree add command. This adds the
contents of the external repository to a subdirectory in your main repository.
git subtree add --prefix=<subdirectory> <repository-url> <branch>
git subtree add --prefix=libs/another-project https://github.com/username/another-project.git
main
• This adds the main branch of the repository another-project.git to the subdirectory libs/another-project
in your repository.
Pull and push Subtree
• To pull in updates from the external repository, use the git subtree pull command. This pulls new
commits from the external project and integrates them into your project.
git subtree pull --prefix=<subdirectory> <repository-url> <branch>
E.g. git subtree pull --prefix=libs/another-project https://github.com/username/another-project.git main
• This pulls the latest changes from the main branch of another-project.git into the libs/another-project
directory in your project.

• If you make changes to the files in the subtree and want to push those changes back to the original
external repository, use git subtree push.
git subtree push --prefix=<subdirectory> <repository-url> <branch>
E.g. git subtree push --prefix=libs/another-project https://github.com/username/another-project.git
main
• This pushes your changes from the libs/another-project directory back to the main branch of the
another-project.git repository.
Split Subtree
• If you want to split a subdirectory into its own repository, you can use git subtree split. This command
extracts the commit history of a specific directory into a separate branch or repository.
git subtree split --prefix=<subdirectory> -b <new-branch>
E.g. git subtree split --prefix=libs/another-project -b another-project-branch
• This creates a new branch another-project-branch containing only the commit history of the libs/another-
project directory.
Practical use case of Submodule and Subtree
• Suppose you're working on a web application that relies on a shared
authentication service (AuthService) and a common UI component library
(UIComponents). These services are maintained as separate repositories because
multiple projects in the company use them. You need to include these services in
your main web application and keep them updated across different projects.
• Project Structure:
• MainWebApp: The main web application repository.
• AuthService: A separate repository that handles user authentication.
• UIComponents: A separate repository containing shared UI components like buttons,
forms, etc.
• The goal is to integrate AuthService and UIComponents into MainWebApp, with
the flexibility to update these services independently, as well as merge updates
from their repositories back into MainWebApp.
Implementing using Submodule
• In case of submodule, goal is to keep both AuthService and UIComponents as
independent repositories
• # Clone the MainWebApp repository
git clone https://github.com/yourcompany/MainWebApp.git
cd MainWebApp
• # Add AuthService as a submodule
git submodule add https://github.com/yourcompany/AuthService.git services/AuthService
• # Add UIComponents as a submodule
git submodule add https://github.com/yourcompany/UIComponents.git libraries/UIComponents
• The submodules are added as independent repositories, and the commit reflects
the specific commits from the external repositories:
git add .gitmodules services/AuthService libraries/UIComponents
git commit -m "Added AuthService and UIComponents as submodules“
Implementing using Submodule (Contd)
• When you or another developer wants to update AuthService or
UIComponents, you’ll need to manually fetch the latest changes in those
submodules.
• # Navigate into AuthService submodule and pull latest changes
cd services/AuthServicegit pull origin main
• # Navigate into UIComponents submodule and pull latest changes
cd ../../libraries/UIComponents
git pull origin main
• # Go back to the main project directory and commit submodule changes
cd ../..git
add services/AuthService libraries/UIComponents
git commit -m "Updated submodules AuthService and UIComponents"
Implementing using Subtree
• With subtree, you can directly integrate AuthService and UIComponents directly
into your project structure.
• # Clone the MainWebApp repository
git clone https://github.com/yourcompany/MainWebApp.git
cd MainWebApp
• # Add AuthService as a subtree
git subtree add --prefix=services/AuthService https://github.com/yourcompany/AuthService.git main --squash

• # Add UIComponents as a subtree


git subtree add --prefix=libraries/UIComponents https://github.com/yourcompany/UIComponents.git main --squash

• Here, the contents of AuthService are placed in the services/AuthService/ folder


and UIComponents in libraries/UIComponents/. These components now appear
as part of the MainWebApp repository, but they maintain a connection to their
original repositories.
Implementing using Subtree (Contd)
• The subtree commits are squashed into a single commit, meaning the history of AuthService and
UIComponents is collapsed into one commit in the main repository:
git commit -m "Added AuthService and UIComponents as subtrees“
• When AuthService or UIComponents are updated in their respective repositories, you can pull the
changes directly into MainWebApp using the following commands:
• # Pull updates from AuthService's main branch
git subtree pull --prefix=services/AuthService https://github.com/yourcompany/AuthService.git main --squash
• # Pull updates from UIComponents' main branch
git subtree pull --prefix=libraries/UIComponents https://github.com/yourcompany/UIComponents.git main --squash
• This will pull the latest changes from the external repositories and integrate them into MainWebApp.
• If you make changes to AuthService or UIComponents within MainWebApp, you can push those
changes back to the external repositories.
• # Push changes made in AuthService back to its repository
git subtree push --prefix=services/AuthService https://github.com/yourcompany/AuthService.git main
• # Push changes made in UIComponents back to its repository
git subtree push --prefix=libraries/UIComponents https://github.com/yourcompany/UIComponents.git main
Comparison
Aspect Submodule Subtrees
Keeps external repositories separate Integrates external repositories
Repository Structure
and independent. directly into the main project.
Setup Complexity Requires initializing and updating Simple, no need for manual
submodules manually. initialization or update commands.
History Management Maintains full history of the external Option to squash history for a cleaner
repositories. Git history.
Working with Branches Must switch branches manually in Branches in the subtree are handled
submodules. seamlessly within the main project.
Update Workflow Updates require navigating into Updates can be pulled directly into the
submodules and pulling changes. main project.

Push Changes Back Can push changes back to the Can push changes back to the external
submodule’s repository. repository.
Merge Conflicts Can lead to complex conflicts if the Easier to manage conflicts as subtrees
submodule and main repo are both are part of the main repo.
modified.
Git squashing
• Squashing refers to the process of combining multiple commits into a
single commit. This is useful for cleaning up your commit history,
particularly when you have made a series of small or experimental
commits, but you only want to present one meaningful change to your
main branch or during a pull request.
• Use Cases for Squashing Commits:
• Cleaning up messy history: If you've made several "work-in-progress" (WIP)
commits while working on a feature and you only want to present a single clean
commit.
• Simplifying code review: When opening a pull request, squashing commits ensures
the reviewer sees one clear change instead of many intermediate commits.
• Merging features: When merging a feature branch into main, squashing ensures
the branch’s work appears as a single commit in the main history.
Squash during merge
• If you’re merging a feature branch into main and you want to squash all of the
feature branch’s commits into one, you can use the --squash option when
merging.
• First, check out the branch you want to merge into (e.g., main):
git checkout main
• Then perform the merge with the --squash option:
git merge --squash feature-branch
• Git will take all the changes from feature-branch and stage them in your working
directory as a single commit. Now you just need to commit the changes:
git commit -m "Merged feature-branch with squash"
• This will create a single commit that includes all the changes from feature-
branch, but without keeping the individual commits from that branch.
Squash local changes
• For squashing all the local changes, you can use reset. This
method works well if you have unpushed commits and want to
squash them before pushing.
• Use git reset to undo all the commits but keep the changes
staged:
git reset --soft HEAD~3 #Reset the last 3 commits but leave the changes staged.
• commit all the changes as a single commit:
git commit -m "Combined changes into one commit"
Exiting editor
• Press i to enter inline insert mode.
• Type the description at the top
• Press ESC to exit insert mode.
• Type :x! and press ENTER
Sparse checkout
Sparse checkout
• Sparse checkout is a Git feature that allows you to check out only a subset of files from the
repository instead of downloading the entire repository content. This is particularly useful when
you're working with a large repository and only need to work with specific directories or files.
• When cloning a repository, use the --no-checkout option so that Git doesn’t check out the files
immediately.
git clone --no-checkout <repository-url>
• Once the repository is cloned, you can enable sparse checkout:
git sparse-checkout init
• You need to tell Git which files or directories to include in your checkout. This is done by adding
paths to the sparse checkout configuration:
git sparse-checkout set <path1> <path2> ...
E.g. git sparse-checkout set bmx/bmx_xxxx spi/spi_xxxx
• Once you have set the sparse patterns, you can now check out the desired files from the
repository:
git checkout
Folder structure - 1
Folder Structure

BMX SPI bmx_xxxx spi_xxxx

IC OC
bmx_yyyy spi_yyyy
Module_repo
BMX SPI

bmx_xxxx

spi_xxxx
Pegasus_repo
Sparse checkout to Pegasus_repo
• Navigate to the location where perseus_repo should be:
cd /path/to/perseus_repo
• Add module_repo as a remote to perseus_repo, so you can pull the
bmx_xxxx directory from it
git remote add module_repo /path/to/module_repo #local repo
git remote add module_repo <url_of_module_repo> # remote repo
• Enable sparse-checkout in Pegasus_repo
git sparse-checkout init
• You now need to configure the sparse checkout file to include only the
bmx_xxxx directory.
git sparse-checkout set bmx/bmx_xxxx
Pull directories to Pegasus_repo
• Now, we need to pull the bmx_xxxx into Pegasus_repo. If we use
pull command, then it will pull all the directories into bmx_xxxx
and merges it with Pegasus_repo. This is not our intention. To avoid
this, we first fetch the changes from bmx_xxxx which is in
module_repo. This fetches the changes from module_repo without
applying them directly to perseus_repo. After fetching, you can
selectively apply only the changes you need
git fetch module_repo main
• Once you've fetched the changes, you can manually merge only the
specific content (in this case, bmx_xxxx):
git checkout FETCH_HEAD -- bmx/bmx_xxxx
Making changes and updating Pegasus_repo
• Once sparse checkedout, the requested folders will be in pegasus_repo. If
you need to push the same, Git doesn’t yet treat it as a "change" unless you
modify or create files in it. To force Git to recognize it, you can add a
placeholder file, modify an existing file or touch a file to mark it as modified.
• You can create a .gitkeep file in bmx_xxxx to ensure the folder is included in
the commit
touch bmx/bmx_xxxx/.gitkeep
• Stage the changes and commit.
git add bmx/bmx_xxxx
git commit -m "Add bmx_xxxx to perseus_repo“
• Push the changes
git push
Making changes and updating module_repo
• Once changes are made in working repo and the same changes needs to be pushed to module_repo, then we might encounter
error: Updates were rejected because the tip of your current branch is behind its remote counterpart. This happens because your
local perseus_repo is out of sync with the latest changes in module_repo. This means that before you can push your changes
from perseus_repo to module_repo, you need to bring your local branch up to date with the latest commits from module_repo.
• To resolve this, first, fetch the latest changes from module_repo without merging them.
git fetch module_repo main
• To show you the differences between your local main branch and the main branch in module_repo.
git log --oneline module_repo/main..main
• Now, to avoid pulling unnecessary directories and only work with bmx_xxxx, you can proceed with a merge that focuses only on
the paths relevant to your sparse-checkout.
git merge module_repo/main --no-commit #stage the merge but won’t commit yet
• Manually resolve if there are any conflicts and add them to staging area and then commit.
git add bmx/bmx_xxxx/appl.txt # Or any conflicting file
git commit -m "Merge latest changes from module_repo“
• Now that your local branch is up to date with module_repo, you can safely push your changes:
git subtree push --prefix=bmx/bmx_xxxx module_repo main

• Alternatively, If you are certain that the only change you want to push from perseus_repo to module_repo is the update to
bmx_xxxx, and you don’t care about the other changes in module_repo, you could force push:
git push --force-with-lease module_repo main
In case you delete a sparse-checkedout folder
• Suppose you sparse-checkout a folder, push the changes. Now if you
delete it from repo and update the remote, then the sparse-checkout
folder wont appear in pegasus_repo.
• When you delete the directory and push the changes, Git treats it as
a removal, so the directory is no longer part of the history at the
latest commit. As a result, sparse checkout won't be able to bring it
back since it's missing from the current commit.
• To resolve this, find the commit where sub-directory was deleted.
git log -- bmx/bmx_xxxx # show the commit history involving bmx_xxxx
• You can revert the commit using commit hash.
git revert <commit_hash> # create a new commit that restores bmx_xxxx to the repository.
Folder structure - 2
Folder Structure

BMX SPI bmx_xxxx spi_xxxx

IC OC
bmx_yyyy spi_yyyy
Module_repo
BMX SPI

bmx_xxxx
bmx_xxxx

spi_xxxx
bmx_yyyy
Pegasus_repo
bmx_branch
Note while creating module_repo
• Once you clone module_repo to local, you will add all the directories related to it.
• You can add origin if there is no remote.
git remote add origin <repo url>
• You need to pull once
git pull
• Then you can set a name to upstream
git branch --set-upstream-to=origin/main main
• You can create a branch out of main.
• The new branch would contain all the folders. Manually delete folders which are not required
and push it to remote.
Branching bmx from module_repo (Not a good approach)
• bmx directory needs to be branched into bmx_branch.
• First create a branch from module_repo
git checkout -b bmx_branch
• This branch contains all the folders of module_repo. But we want only
bmx. Use filter-repo and remove other folders
git filter-repo --path bmx/ --force # removes all
other folders and
retains only the history
of bmx directory
• Push the branch to remote.
git push -u origin bmx_branch
• Note that the approach removes all the remotes in local. Hence not a good approach
Sparse checkout to Pegasus_repo
• Navigate to the location where perseus_repo should be:
cd /path/to/pegasus_repo
• Add module_repo as a remote to pegasus_repo, so you can pull the
bmx_xxxx directory from it
git remote add module_repo /path/to/module_repo #local repo
git remote add module_repo <url_of_module_repo> # remote repo
• Enable sparse-checkout in Pegasus_repo
git sparse-checkout init
• You now need to configure the sparse checkout file to include only the
bmx_xxxx directory.
git sparse-checkout set bmx/bmx_xxxx
Pull directories to Pegasus_repo
• Now, we need to pull the bmx_xxxx into Pegasus_repo. If we use pull
command, then it will pull all the directories into bmx_xxxx and merges
it with Pegasus_repo. This is not our intention. To avoid this, we first
fetch the changes from bmx_xxxx which is in module_repo. This fetches
the changes from module_repo without applying them directly to
perseus_repo. After fetching, you can selectively apply only the changes
you need
git fetch module_repo bmx_branch #from branch
git fetch module_repo tag <tagname> #from tag
• Now the FETCH_HEAD points to bmx/bmx_xxxx directory. bmx_xxxx is
ready for checkout.
git checkout FETCH_HEAD -- bmx/bmx_xxxx
Making changes and updating Pegasus_repo
• Once sparse checkedout, the requested folders will be in pegasus_repo. If
you need to push the same, Git doesn’t yet treat it as a "change" unless you
modify or create files in it. To force Git to recognize it, you can add a
placeholder file, modify an existing file or touch a file to mark it as modified.
• You can create a .gitkeep file in bmx_xxxx to ensure the folder is included in
the commit
touch bmx/bmx_xxxx/.gitkeep
• Stage the changes and commit.
git add bmx/bmx_xxxx
git commit -m "Add bmx_xxxx to perseus_repo“
• Push the changes
git push
Pushing changes to bmx_branch
• You should be in sparse-checkout mode to push any changes to bmx_branch
• Push your changes from perseus_repo to the bmx_branch of module_repo without affecting
the main branch:
git push module_repo main:bmx_branch --force
Tags cannot be updated
• This command will push the changes you made in the main branch of perseus_repo directly to
bmx_branch in module_repo.
• Force is used because bmx_branch will not have same history as module_repo since folders
would have been deleted.
• Go to module_repo->bmx_branch
cd path/to/bmx_branch
• Merge the changes by pulling in from remote with local directory
git pull.
• Push the changes into remote
git push
Push changes from bmx_branch to module_repo
• All the changes done in pegasus_repo is pushed to bmx_branch.
• bmx_branch is pushed to remote
• bmx_branch needs to be merged into module_repo
• Checkout the main branch
git checkout main
• Checkout bmx folder from bmx_branch. bmx folder would be available for
adding
git checkout bmx_branch -- bmx/
• Add the checked out folder and commit
git add bmx/
git commit –m<message>
Filter-repo
Installing filter-repo
• Install filter-repo using pip install git-filter-repo. Add pip to environmental
variables path if its not already added to install from pip.
• Make git-filter-repo.py accessible to git by adding its path to environmental
path system variables.
c/Users/i15600/AppData/Local/Programs/Python/Python312/Scripts/git-filter-repo.py
• Add an alias in Git Bash for easier access to the script.
alias git-filter-repo='c/Users/i15600/AppData/Local/Programs/Python/Python312/Scripts/git-filter-repo.py’
• You can now test whether git filter-repo is installed correctly by running:
git filter-repo --version
Creating empty branch
Creating empty branch
• Create branch first
git checkout -b <branch_name>
• Use below command to remove all folders
git rm -rf *
• Use below command to checkout individual folders
git checkout main <folder>
• This should include only the required folders.
• Then stage the folders and commit, else it will delete the folders from main
branch.

You might also like