diff --git a/.dockerignore b/.dockerignore
index 8ba0791..9d8b3f9 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -2,7 +2,6 @@
 etc/
 lib/
 .github/
-tests/
 
 *.md
 gitconvex-k8s.yml
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index bfe85c0..973d455 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -79,6 +79,7 @@ jobs:
       #    uses a compiled language
 
       - run: |
+          export GITCONVEX_DEFAULT_PATH=$(pwd)
           make build-server
 
       - name: Perform CodeQL Analysis
diff --git a/.github/workflows/go-collab.yml b/.github/workflows/go-collab.yml
index db366e6..9851be5 100644
--- a/.github/workflows/go-collab.yml
+++ b/.github/workflows/go-collab.yml
@@ -14,12 +14,13 @@ jobs:
           brew install libssh2
           brew install libgit2
 
-  gitconvex-integration-test:
+  gitconvex-test:
     name: Gitconvex server test
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
-      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/starfleet
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
+      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/gitconvex-test
+      GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -36,24 +37,29 @@ jobs:
       - name: Check out code into the Go module directory
         uses: actions/checkout@v2
 
-      - name: Run Go Test
+      - name: Setup Test Artifacts
         run: |
-          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/lib* /usr/lib
-          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/:$PATH"
+          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/lib* /usr/lib
+          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/:$PATH"
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
-          go test -v ./...
+
+      - name: Run Go Test
+        shell: bash
+        run: |
+          export PATH=$PATH:$(go env GOPATH)/bin
+          make test-ci-pretty
 
   gitconvex-build:
     needs:
-      - gitconvex-integration-test
+      - gitconvex-test
       - libgit2-setup-test
 
     name: Gitconvex Build
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -76,13 +82,13 @@ jobs:
   gitconvex-mock-integration:
     needs:
       - libgit2-setup-test
-      - gitconvex-integration-test
+      - gitconvex-test
       - gitconvex-build
 
     name: Mocking Gitconvex Unified Repo Integration
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -103,7 +109,7 @@ jobs:
         run: |
           go get -v -t -d ./...
 
-      - name: Integration checkup
+      - name: Test deployment prep to integrated repo
         run: |
           export TARGET_BRANCH=${{ secrets.TARGET_BRANCH }}
           git clone https://github.com/neel1996/gitconvex-server.git $HOME/gitconvex-server
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index b74479a..c9f5807 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -14,12 +14,14 @@ jobs:
           brew install libssh2
           brew install libgit2
 
-  gitconvex-integration-test:
+  gitconvex-test:
     name: Gitconvex server test
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
-      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/starfleet
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
+      GITCONVEX_TEST_REPO: /home/runner/work/gitconvex-server/gitconvex-test
+      GITCONVEX_DEFAULT_PATH: /usr/local/gitconvex
+      COVERAGE_THRESHOLD: 90
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -36,24 +38,37 @@ jobs:
       - name: Check out code into the Go module directory
         uses: actions/checkout@v2
 
-      - name: Run Go Test
+      - name: Setup Test Artifacts
         run: |
-          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/lib* /usr/lib
-          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/:$PATH"
+          sudo cp /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/lib* /usr/lib
+          export PATH="/home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/:$PATH"
           git config --global user.name "${{ secrets.ACTION_USER_NAME }}" && git config --global user.email "${{ secrets.ACTION_USER_EMAIL }}"
           sudo mkdir -p /usr/local/gitconvex
           sudo chown $(whoami) /usr/local/gitconvex/
-          go test -v ./...
+
+      - name: Run Go Test
+        shell: bash
+        run: |
+          export PATH=$PATH:$(go env GOPATH)/bin
+          make test-ci-pretty
+
+      - name: Check Coverage
+        shell: bash
+        run: |
+          export COVERAGE_PERCENT=`go tool cover -func=coverage.out | grep "total:" | grep -Eo '[0-9]+\.[0-9]+'`
+          echo "Current coverage percentage : $COVERAGE_PERCENT"
+          make check-coverage
+
 
   gitconvex-build:
     needs:
-      - gitconvex-integration-test
+      - gitconvex-test
       - libgit2-setup-test
 
     name: Gitconvex Build
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -76,13 +91,13 @@ jobs:
   gitconvex-bundle:
     needs:
       - libgit2-setup-test
-      - gitconvex-integration-test
+      - gitconvex-test
       - gitconvex-build
 
     name: Gitconvex Unified Repo Integration
     runs-on: ubuntu-latest
     env:
-      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.0/lib/pkgconfig/
+      PKG_CONFIG_PATH: /home/linuxbrew/.linuxbrew/Cellar/libgit2/1.1.1/lib/pkgconfig/
 
     steps:
       - name: Install libgit2 from Homebrew
@@ -103,7 +118,7 @@ jobs:
         run: |
           go get -v -t -d ./...
 
-      - name: Integration checkup
+      - name: Deploy to integrated repo
         run: |
           export TARGET_BRANCH=${{ secrets.TARGET_BRANCH }}
           git clone https://github.com/neel1996/gitconvex-server.git $HOME/gitconvex-server
diff --git a/.gitignore b/.gitignore
index 76a17a9..219510e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,15 @@
 build/
 .idea/
 database/
+ui/
+dist/
+gitconvex-test/
+
 env_config.json
 gitclient
+coverage.out
 /*.exe
 /*.dll
+gitconvex
+gitconvex-server
+/local_env_set.sh
diff --git a/LIBGIT_NOTES.md b/LIBGIT_NOTES.md
index 8838d5a..1946ee3 100644
--- a/LIBGIT_NOTES.md
+++ b/LIBGIT_NOTES.md
@@ -66,6 +66,8 @@ Following the above steps will make `libgit2` available as a shared library for
 
 #### For Linux (tested on Ubuntu 20.04)
 
+>If you have brew installed on your linux machine then you can follow the same instructions [mentioned below for MacOS](#for-macos) to setup libgit2 
+
 Make sure you have the following packages installed on your system
 
 - [cmake](https://cmake.org/download/)
@@ -73,7 +75,7 @@ Make sure you have the following packages installed on your system
 - [wget](https://www.gnu.org/software/wget/)
 - [gcc](https://gcc.gnu.org/)
 
-Make sure you have required rights for running the following commands. If any of these fail due to access errors, then
+Make sure you have required rights for running the following commands. If any of these fail due to access errors then
 try with `sudo`
 
 ```shell
@@ -110,11 +112,12 @@ The dependencies required to build and run gitconvex are readily available from
 
 Download and setup [brew](https://brew.sh/) to install all the required packages
 
+- [libssh2](https://formulae.brew.sh/formula/libssh2)
+  ```shell
+  brew install libssh2
+  ```
+  
 - [libgit2](https://formulae.brew.sh/formula/libgit2)
   ```shell
   brew install libgit2
   ```
-- [libssh2](https://formulae.brew.sh/formula/libssh2)
-  ```shell
-  brew install libssh2
-  ```
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 51206dc..fadd138 100644
--- a/Makefile
+++ b/Makefile
@@ -1,50 +1,82 @@
 get:
 	go get
+
 run:
 	go run server.go
+
 build-ui:
-	git clone https://github.com/neel1996/gitconvex-ui.git ui/
-	cd ui
-	npm install
-	export NODE_ENV=production
-	npm i -g create-react-app tailwindcss@1.6.0
-	npm run build:tailwind
-	npm run build
-	mv ./build ../
+	@./build_scripts/build_ui.sh
+
 build-server:
-	mkdir -p ./dist
-	go build -o ./dist
-
-build:
-	@echo "⚒️ Initiating gitconvex build"
-	@echo "🗑️ Cleaning up old directories"
-	@rm -rf ui/ dist/ build/
-	@echo "⏬ Cloning gitconvex react repo"
-	@git clone -q https://github.com/neel1996/gitconvex-ui.git ui/ && \
-	cd ui && \
-	echo "⏳ Installing UI dependencies..." && \
-	npm install --silent && \
-	export NODE_ENV=production && \
-	npm install tailwindcss postcss autoprefixer && \
-	npx tailwindcss build -o ./src/index.css -c ./src/tailwind.config.js && \
-	rm package-*.json && \
-	rm -rf .git/ && \
-	echo "🔧 Building react UI bundle" && \
-	npm run build && \
-	mv ./build ../ && \
-	cd .. && \
-	mkdir -p ./dist && \
-	mv build/ ./dist/ && \
-	mv ./dist/build ./dist/gitconvex-ui
-	echo "🚀 Building final go source with UI bundle" && \
-	go build -v -a -o ./dist && \
-	echo "Gitconvex build completed!" && \
-	mv ./dist/gitconvex-server ./dist/gitconvex 
-	@echo "Installing libs"
+	@./build_scripts/build_server.sh
+
+clean:
+	@echo "💨 Cleaning up previous build and bundles..."
+	@rm -rf ui/ dist/ gitconvex build/
+
+bundle:
+	@mkdir -p ./dist && \
+    mv ./build/ ./dist/ && \
+    mv ./dist/build ./dist/gitconvex-ui;
+
+pack:
+	cd ./dist && \
+	tar -cvzf gitconvex-$$GITCONVEX_VERSION.tar.gz .
+
+build: clean build-ui bundle build-server
 	@echo "✅ Gitconvex Build Completed successfully!"
 	@echo "📬 Use ./dist/gitconvex to start Gitconvex on port 9001"
 	@echo "📬 Try ./dist/gitconvex --port PORT_NUMBER to run gitconvex on the desired port"
+
+git-testuser-setup:
+	git config --global user.name "test"
+	git config --global user.email "test@test.com"
+
 test:
-	go test -tags static -v ./...
+	export GITCONVEX_TEST_REPO="$(PWD)/gitconvex-test" && \
+	export GITCONVEX_DEFAULT_PATH="$(PWD)/gitconvex-test" && \
+	rm -rf $$GITCONVEX_TEST_REPO && \
+ 	go clean --cache && \
+ 	./build_scripts/remove_test_repo.sh && \
+ 	./build_scripts/clone_test_repo.sh && \
+ 	go test ./... -count=1 -cover -coverprofile=coverage.out && \
+	rm -rf $$GITCONVEX_TEST_REPO
+
+test-pretty:
+	export GITCONVEX_TEST_REPO="$(PWD)/gitconvex-test" && \
+	export GITCONVEX_DEFAULT_PATH="$(PWD)/gitconvex-test" && \
+	rm -rf $$GITCONVEX_TEST_REPO && \
+ 	go clean --cache && \
+ 	./build_scripts/remove_test_repo.sh && \
+ 	./build_scripts/clone_test_repo.sh && \
+ 	gotestsum ./... -count=1 -p=1 -cover -coverprofile=coverage.out && \
+	rm -rf $$GITCONVEX_TEST_REPO
+
+test-ci: git-testuser-setup
+	go generate && \
+	go clean --cache && \
+    sh ./build_scripts/clone_test_repo.sh && \
+    go test ./... -count=1 -p=1 -cover -coverprofile=coverage.out && \
+    rm -rf $$GITCONVEX_TEST_REPO
+
+test-ci-pretty: git-testuser-setup
+	go generate && \
+	go clean --cache && \
+    sh ./build_scripts/clone_test_repo.sh && \
+    go get gotest.tools/gotestsum && \
+    gotestsum ./... -count=1 -p=1 -cover -coverprofile=coverage.out && \
+    rm -rf $$GITCONVEX_TEST_REPO
+
+dockerise-test:
+	rm -rf $$GITCONVEX_TEST_REPO && \
+	docker-compose -f docker-compose.test.yaml build && \
+	docker-compose -f docker-compose.test.yaml up
+
+check-coverage:
+	bash ./build_scripts/check_coverage.sh
+
+show-coverage:
+	go tool cover -html=coverage.out
+
 start:
 	./dist/gitconvex
diff --git a/README.md b/README.md
index 253b468..b141886 100644
--- a/README.md
+++ b/README.md
@@ -12,12 +12,9 @@ This is the back-end go source repo for the [gitconvex](https://github.com/neel1
 
 ## Dependencies
 
-The dependency packages used by this project can be
-found [here](https://github.com/neel1996/gitconvex-server/network/dependencies)
-
-- **📜 Git Library** - The project uses [git2go](https://github.com/libgit2/git2go) library for all the git operations
-  without relying on the native git client
-- **📈 GraphQL** - [gqlgen](https://github.com/99designs/gqlgen) is used for generating boiler plate GraphQL code which
+- **📜 Git Library** - The project uses [git2go](https://github.com/libgit2/git2go) library for performing all the git
+  operations
+- **📈 GraphQL** - [gqlgen](https://github.com/99designs/gqlgen) is used for generating boiler-plate GraphQL code which
   is the backbone of the whole project
 - **📡 HTTP Router** - [mux](https://github.com/gorilla/mux) is used as the HTTP router for graphql playground and sets
   a handler for the API entry point
@@ -28,139 +25,24 @@ The project uses **git2go** - A libgit2 based binding for go to handle all the g
 properly to run the project.
 
 Follow [these](https://libgit2.org/docs/guides/build-and-link/) instructions to build libgit2
-from [soruce](https://github.com/libgit2/libgit2). Follow this only if you have openssl and libssh setup in your
-machine. If this is not the case then follow the detailed instructions mentioned in [LIBGIT_NOTES](LIBGIT_NOTES.md) for a
-step-by-step guide
+from [source](https://github.com/libgit2/libgit2). Follow this only if you have openssl and libssh setup in your
+machine. If this is not the case then follow the detailed instructions mentioned in [LIBGIT_NOTES](LIBGIT_NOTES.md) for
+a step-by-step guide
 
 If you stumble upon any challenges, then use [this](https://github.com/neel1996/gitconvex-server/discussions/7)
 discussion forum for assistance
 
 ### Contribution Guidelines
 
-Fork the repo and raise a new Pull Request to merge your branch with the `main` branch of this repo. Once the
-review is complete, the PR will be approved and merged
+Fork the repo and raise a new Pull Request to merge your changes with the `main` branch of this repo. Once the review is
+complete, the PR will be approved and merged
 
 ## Gitconvex as a Git API
 
-Gitconvex can function as a service without the UI. The whole API is built with graphql and the underlying queries & mutations can be accessed by invoking `http://localhost:9001/gitconvexapi`. GraphQL playground is also enabled to experiment with the GQL queries and mutations and it can be accessed from `http://localhost:9001/gitconvexapi/graph`
-
-![gql-playground](https://user-images.githubusercontent.com/47709856/113421107-248f5100-93e8-11eb-8c22-9f6337f7c25f.png)
-
-## Project directory tree
-
-**📂 api** - All the common api modules which does not modify the git repo in anyway resides in this directory
-
-**📂 git** - The files in this directory will handle all the git related operations behind the scenes using `go-git` and
-the native `git` client
+Gitconvex can function as a service without the UI. The whole API is build with graphql, and the underlying
+queries/mutations can be accessed by invoking `http://localhost:9001/gitconvexapi`.
 
-**📂 graph** - The GQL schema and other files which are used for enabling GQL based communication are included in this
-directory.
-
-**📂 tests** - As the name suggests, all the test scripts are stored here
-
-**📂 utils** - The common utility modules which are required by other functions to execute common tasks are stored in
-this directory
-
-```
-├── api
-│   ├── add_repo.go
-│   ├── code_file_view.go
-│   ├── fetch_repo.go
-│   ├── health_check.go
-│   ├── repo_status.go
-│   ├── settings_api.go
-│   └── update_repo_name.go
-├── etc
-│   ├── cygwin1.dll
-│   ├── git2.dll
-│   ├── pageant.exe
-│   ├── putty.exe
-│   └── puttygen.exe
-├── git
-│   ├── git_branch_add.go
-│   ├── git_branch_checkout.go
-│   ├── git_branch_compare.go
-│   ├── git_branch_delete.go
-│   ├── git_branch_list.go
-│   ├── git_changed_files.go
-│   ├── git_clone.go
-│   ├── git_commit_changes.go
-│   ├── git_commit_compare.go
-│   ├── git_commit_files.go
-│   ├── git_commit_log_search.go
-│   ├── git_commit_logs.go
-│   ├── git_fetch.go
-│   ├── git_fileline_diff.go
-│   ├── git_init.go
-│   ├── git_ls_files.go
-│   ├── git_pull.go
-│   ├── git_push.go
-│   ├── git_remote_add.go
-│   ├── git_remote_allremotedata.go
-│   ├── git_remote_callbacks.go
-│   ├── git_remote_delete.go
-│   ├── git_remote_edit.go
-│   ├── git_repo.go
-│   ├── git_repo_validate.go
-│   ├── git_reset_item.go
-│   ├── git_resetall_items.go
-│   ├── git_stage_item.go
-│   ├── git_stageall_items.go
-│   ├── git_total_commits.go
-│   └── git_unpushed_commits.go
-├── gitconvex-k8s.yml
-├── gitconvex-ui
-├── global
-│   ├── GlobalLogger.go
-│   ├── common_strings.go
-│   ├── current_version.go
-│   ├── errors.go
-│   └── status_strings.go
-├── go.mod
-├── go.sum
-├── gqlgen.yml
-├── graph
-│   ├── generated
-│   │   └── generated.go
-│   ├── model
-│   │   ├── aux_models.go
-│   │   └── models_gen.go
-│   ├── resolver.go
-│   ├── schema.graphqls
-│   └── schema.resolvers.go
-├── make.bat
-├── server.go
-├── tests
-│   ├── beforeAll_git_clone_test.go
-│   ├── code_file_view_test.go
-│   ├── encrypt_https_password_test.go
-│   ├── git_branch_add_test.go
-│   ├── git_branch_delete_test.go
-│   ├── git_branch_test.go
-│   ├── git_changed_files_test.go
-│   ├── git_commit_changes_test.go
-│   ├── git_commit_compare_test.go
-│   ├── git_commit_files_test.go
-│   ├── git_commit_log_search_test.go
-│   ├── git_commit_logs_test.go
-│   ├── git_ls_files_test.go
-│   ├── git_remote_add_test.go
-│   ├── git_remote_allremotedata_test.go
-│   ├── git_remote_data_test.go
-│   ├── git_remote_delete_test.go
-│   ├── git_remote_edit_test.go
-│   ├── git_resetall_items_test.go
-│   ├── git_total_commits_test.go
-│   ├── git_unpushed_commits_test.go
-│   ├── health_check_test.go
-│   └── update_repo_name_test.go
-└── utils
-    ├── db_file_reader.go
-    ├── db_file_writer.go
-    ├── encrypt_https_password.go
-    ├── env_file_handler.go
-    └── git_standalone_client.go
-
-10 directories, 88 files
-```
+GraphQL playground is enabled to experiment with the GQL queries and mutations. It can be accessed
+from `http://localhost:9001/gitconvexapi/graph`
 
+![gql-playground](https://user-images.githubusercontent.com/47709856/113421107-248f5100-93e8-11eb-8c22-9f6337f7c25f.png)
diff --git a/Test.Dockerfile b/Test.Dockerfile
new file mode 100644
index 0000000..b44c246
--- /dev/null
+++ b/Test.Dockerfile
@@ -0,0 +1,11 @@
+FROM golang:1.16.0-alpine
+
+WORKDIR /home/gitconvex
+
+COPY . .
+
+# Install required packages
+RUN apk update && \
+    apk add --update libgit2-dev libssh2-dev gcc make musl-dev git
+
+
diff --git a/api/add_repo.go b/api/add_repo.go
index bbb5701..d1f7cb7 100644
--- a/api/add_repo.go
+++ b/api/add_repo.go
@@ -164,6 +164,7 @@ func (inputs AddRepoInputs) AddRepo() *model.AddRepoParams {
 	userName := inputs.UserName
 	password := inputs.Password
 	sshKeyPath := inputs.SSHKeyPath
+	repoValidator := git.NewRepoValidator(repoPath, nil)
 
 	if cloneSwitch && len(repoURL) > 0 {
 		currentOs := HealthCheckApi().Os
@@ -208,7 +209,7 @@ func (inputs AddRepoInputs) AddRepo() *model.AddRepoParams {
 		}
 	}
 
-	_, invalidRepoErr := git.RepoValidator(repoPath)
+	invalidRepoErr := repoValidator.ValidateRepoWithPath()
 
 	if invalidRepoErr != nil && !initSwitch {
 		logger.Log(fmt.Sprintf("The repo is not a valid git repo\n%v", invalidRepoErr), global.StatusError)
diff --git a/api/repo_status.go b/api/repo_status.go
index 5c508f8..9a2dfb7 100644
--- a/api/repo_status.go
+++ b/api/repo_status.go
@@ -2,21 +2,24 @@ package api
 
 import (
 	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/model"
 	"github.com/neel1996/gitconvex/utils"
 	"strings"
 )
 
+//TODO: This is a temporary function and will be replaced with an clean interface over the course of refactoring
+
 // RepoStatus collects the basic details of the target repo and returns the consolidated result
 func RepoStatus(repoId string) *model.GitRepoStatusResults {
-	logger := global.Logger{}
 	logger.Log("Collecting repo status information", global.StatusInfo)
 
 	repoChan := make(chan git.RepoDetails)
-	remoteChan := make(chan git.RemoteDataModel)
-	branchChan := make(chan git.Branch)
-	commitChan := make(chan git.AllCommitData)
+	//commitChan := make(chan commit.AllCommitData)
 	trackedFileCountChan := make(chan int)
 
 	var repoObject git.RepoInterface
@@ -41,21 +44,34 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		}
 	}
 
-	remote := ""
-	var remoteURL *string
-	remoteURL = &remote
+	tempRemote := ""
+	var (
+		remoteURL  *string
+		remoteName string
+	)
+	remoteURL = &tempRemote
 
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo,
-		RemoteURL: *remoteURL,
-	}
+	repoForRemote := middleware.NewRepository(repo)
 
-	go remoteDataObject.RemoteData(remoteChan)
-	remoteData := <-remoteChan
-	remotes := remoteData.RemoteURL
+	remoteValidation := remote.NewRemoteValidation(repoForRemote)
+	remoteList := remote.NewRemoteList(repoForRemote, remoteValidation)
+	remoteUrlList := remote.NewRemoteUrlData(repoForRemote, remoteValidation, remoteList)
+	listRemoteUrl := remote.Operation{ListRemoteUrl: remoteUrlList}
+
+	remotes, remoteErr := listRemoteUrl.GitGetAllRemoteUrl()
+	if remoteErr != nil {
+		logger.Log(remoteErr.Error(), global.StatusError)
+		return nil
+	}
 
 	if len(remotes) > 0 && *remotes[0] != "" {
+		remoteNameObject := remote.NewGetRemoteName(
+			repoForRemote,
+			*remotes[0],
+			remoteValidation,
+			remoteList,
+		)
+		remoteName = remoteNameObject.GetRemoteNameWithUrl()
 		sRemote := strings.Split(*remotes[0], "/")
 		repoName = &sRemote[len(sRemote)-1]
 	} else {
@@ -80,25 +96,17 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 		*remoteURL = *remotes[0]
 	}
 
-	var branchListObject git.BranchListInterface
-	branchListObject = git.BranchListInputs{Repo: repo}
-	go branchListObject.GetBranchList(branchChan)
+	branchListObj := branch.NewBranchList(middleware.NewRepository(repo))
+	branchList, _ := branchListObj.ListBranches()
 
-	branchList := <-branchChan
-	currentBranch := &branchList.CurrentBranch
+	currentBranch := branchList.CurrentBranch
 	branches := branchList.BranchList
 	allBranches := branchList.AllBranchList
 
-	var latestCommit *string
-
-	var allCommitObject git.AllCommitInterface
+	listCommitLogs := commit.NewListAllLogs(middleware.NewRepository(repo), nil, nil)
+	totalCommits := commit.NewTotalCommits(listCommitLogs).Get()
 
-	allCommitObject = git.AllCommitStruct{Repo: repo}
-	go allCommitObject.AllCommits(commitChan)
-	commitData := <-commitChan
-	latestCommit = &commitData.LatestCommit
-	totalCommits := commitData.TotalCommits
-	totalCommitsPtr := &totalCommits
+	latestCommitMessage := commit.NewLatestMessage(middleware.NewRepository(repo)).Get()
 
 	var listFilesObject git.ListFilesInterface
 	listFilesObject = git.ListFilesStruct{
@@ -112,12 +120,12 @@ func RepoStatus(repoId string) *model.GitRepoStatusResults {
 	return &model.GitRepoStatusResults{
 		GitRemoteData:        remoteURL,
 		GitRepoName:          repoName,
-		GitBranchList:        branches,
-		GitAllBranchList:     allBranches,
-		GitCurrentBranch:     currentBranch,
-		GitRemoteHost:        remoteData.RemoteHost,
-		GitTotalCommits:      totalCommitsPtr,
-		GitLatestCommit:      latestCommit,
+		GitBranchList:        utils.GeneratePointerArrayFrom(branches),
+		GitAllBranchList:     utils.GeneratePointerArrayFrom(allBranches),
+		GitCurrentBranch:     &currentBranch,
+		GitRemoteHost:        &remoteName,
+		GitTotalCommits:      &totalCommits,
+		GitLatestCommit:      &latestCommitMessage,
 		GitTotalTrackedFiles: trackedFilePtr,
 	}
 }
diff --git a/build_scripts/build_server.sh b/build_scripts/build_server.sh
new file mode 100755
index 0000000..ec042eb
--- /dev/null
+++ b/build_scripts/build_server.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+if [[ "$GITCONVEX_DEFAULT_PATH" == "" ]]; then
+  echo "Default path missing";
+  echo "Please set the default path where gitconvex can maintain its data";
+  echo "========================================="
+  echo "export GITCONVEX_DEFAULT_PATH=/some/path"
+  echo "========================================="
+  exit 1;
+fi
+
+echo "🚀 Building server modules"
+go generate
+go build -v -o ./dist
\ No newline at end of file
diff --git a/build_scripts/build_ui.sh b/build_scripts/build_ui.sh
new file mode 100755
index 0000000..d57eeda
--- /dev/null
+++ b/build_scripts/build_ui.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+echo "⏬ Cloning gitconvex react repo"
+git clone https://github.com/neel1996/gitconvex-ui.git ui/
+cd ui
+
+echo "⏳ Installing UI dependencies..."
+npm install
+export NODE_ENV=production
+npm i -g create-react-app tailwindcss@1.6.0
+npm run build:tailwind
+
+echo "🔧 Building react UI bundle"
+npm run build
+mv ./build ../build
+cd ..
\ No newline at end of file
diff --git a/build_scripts/check_coverage.sh b/build_scripts/check_coverage.sh
new file mode 100644
index 0000000..9b277e9
--- /dev/null
+++ b/build_scripts/check_coverage.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+if [[ $COVERAGE_PERCENT < $COVERAGE_THRESHOLD ]];
+then
+  echo "Coverage $COVERAGE_PERCENT is less that the threshold $COVERAGE_THRESHOLD" && exit 1;
+else
+  echo " ✔️ Good work! Coverage $COVERAGE_PERCENT meets the expectation"
+fi;
\ No newline at end of file
diff --git a/build_scripts/clone_test_repo.sh b/build_scripts/clone_test_repo.sh
new file mode 100755
index 0000000..5c68820
--- /dev/null
+++ b/build_scripts/clone_test_repo.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+git clone https://github.com/neel1996/gitconvex-test.git $GITCONVEX_TEST_REPO
+
+cd $GITCONVEX_TEST_REPO && \
+git config user.name "test" && \
+git config user.email "test@test.com"
+
+git init $GITCONVEX_TEST_REPO/no_head
+
+mkdir no_head_for_commit && \
+touch ./no_head_for_commit/no_head.txt  && \
+git init $GITCONVEX_TEST_REPO/no_head_for_commit
\ No newline at end of file
diff --git a/build_scripts/remove_test_repo.sh b/build_scripts/remove_test_repo.sh
new file mode 100644
index 0000000..8189f89
--- /dev/null
+++ b/build_scripts/remove_test_repo.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+
+echo "Removing test repo $GITCONVEX_TEST_REPO"
+rm -rf $GITCONVEX_TEST_REPO
\ No newline at end of file
diff --git a/constants/errors.go b/constants/errors.go
new file mode 100644
index 0000000..26ba1ed
--- /dev/null
+++ b/constants/errors.go
@@ -0,0 +1,30 @@
+package constants
+
+type ApiError struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	BranchAddError       = ApiError{ErrorCode: "BRANCH_ADD_FAILED", ErrorString: "Failed to add new branch"}
+	BranchCheckoutError  = ApiError{ErrorCode: "CHECKOUT_FAILED", ErrorString: "Failed to checkout branch"}
+	BranchDeleteError    = ApiError{ErrorCode: "BRANCH_DELETE_FAILED", ErrorString: "Failed to delete branch"}
+	RemoteAddError       = ApiError{ErrorCode: "REMOTE_ADD_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteDeleteError    = ApiError{ErrorCode: "REMOTE_DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoteEditError      = ApiError{ErrorCode: "REMOTE_EDIT_FAILED", ErrorString: "Failed to delete add new remote"}
+	FetchFromRemoteError = ApiError{ErrorCode: "FETCH_ERROR", ErrorString: "Failed to delete add new remote"}
+	PullFromRemoteError  = ApiError{ErrorCode: "PULL_ERROR", ErrorString: "Failed to delete add new remote"}
+	StageItemError       = ApiError{ErrorCode: "ADD_ITEM_FAILED", ErrorString: "Failed to delete add new remote"}
+	StageAllItemsError   = ApiError{ErrorCode: "ALL_STAGE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveItemError      = ApiError{ErrorCode: "STAGE_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RemoveAllItemsError  = ApiError{ErrorCode: "STAGE_ALL_REMOVE_FAILED", ErrorString: "Failed to delete add new remote"}
+	PushToRemoteError    = ApiError{ErrorCode: "PUSH_FAILED", ErrorString: "Failed to delete add new remote"}
+	PortUpdateError      = ApiError{ErrorCode: "PORT_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	DataFileUpdateError  = ApiError{ErrorCode: "DATAFILE_UPDATE_FAILED", ErrorString: "Failed to delete add new remote"}
+	RepoDeleteError      = ApiError{ErrorCode: "DELETE_FAILED", ErrorString: "Failed to delete add new remote"}
+)
+
+func (e ApiError) Error() string {
+	return e.ErrorString
+}
diff --git a/constants/global_constants.go b/constants/global_constants.go
new file mode 100644
index 0000000..0c798e2
--- /dev/null
+++ b/constants/global_constants.go
@@ -0,0 +1,11 @@
+package constants
+
+const (
+	SearchLimit = 10
+)
+
+const (
+	Repo       = "GIT_REPO"
+	RemoteName = "REMOTE_NAME"
+	RemoteUrl  = "REMOTE_URL"
+)
diff --git a/controller/branch_controller.go b/controller/branch_controller.go
new file mode 100644
index 0000000..9b658c2
--- /dev/null
+++ b/controller/branch_controller.go
@@ -0,0 +1,79 @@
+package controller
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/branch/checkout"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/models"
+)
+
+type BranchController interface {
+	GitAddBranch(branchName string, isRemoteBranch bool, targetCommit *git2go.Commit) (string, error)
+	GitCheckoutBranch(branchName string) (string, error)
+	GitDeleteBranch(branchName string) (*model.BranchDeleteStatus, error)
+	GitCompareBranches(baseBranch string, compareBranch string) ([]*model.BranchCompareResults, error)
+	GitListBranches() (model.ListOfBranches, error)
+}
+
+type branchController struct {
+	add             branch.Add
+	checkoutFactory checkout.Factory
+	compare         branch.Compare
+	delete          branch.Delete
+	list            branch.List
+}
+
+func (b branchController) GitAddBranch(branchName string, isRemoteBranch bool, targetCommit *git2go.Commit) (string, error) {
+	err := b.add.AddBranch(branchName, isRemoteBranch, targetCommit)
+
+	if err != nil {
+		return global.BranchAddError, err
+	}
+
+	return global.BranchAddSuccess, nil
+}
+
+func (b branchController) GitCheckoutBranch(branchName string) (string, error) {
+	err := b.checkoutFactory.GetCheckoutAction(branchName).CheckoutBranch()
+
+	if err != nil {
+		return global.BranchCheckoutError, err
+	}
+
+	return global.BranchCheckoutSuccess, nil
+}
+
+func (b branchController) GitCompareBranches(baseBranch string, compareBranch string) ([]*model.BranchCompareResults, error) {
+	return b.compare.CompareBranch(baseBranch, compareBranch)
+}
+
+func (b branchController) GitDeleteBranch(branchName string) (*model.BranchDeleteStatus, error) {
+	err := b.delete.DeleteBranch(branchName)
+
+	if err != nil {
+		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}, err
+	}
+
+	return &model.BranchDeleteStatus{Status: global.BranchDeleteSuccess}, nil
+}
+
+func (b branchController) GitListBranches() (model.ListOfBranches, error) {
+	listOfBranches, err := b.list.ListBranches()
+	if err != nil {
+		return model.ListOfBranches{}, err
+	}
+
+	return listOfBranches, nil
+}
+
+func NewBranchController(branchModel models.Branch) BranchController {
+	return branchController{
+		add:             branchModel.Add,
+		checkoutFactory: branchModel.Checkout,
+		compare:         branchModel.Compare,
+		delete:          branchModel.Delete,
+		list:            branchModel.List,
+	}
+}
diff --git a/controller/commit_file_history.go b/controller/commit_file_history.go
new file mode 100644
index 0000000..1165656
--- /dev/null
+++ b/controller/commit_file_history.go
@@ -0,0 +1,40 @@
+package controller
+
+import (
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type CommitFileHistoryController interface {
+	GetCommitFileHistory() ([]*model.GitCommitFileResult, error)
+}
+
+type commitFileHistoryController struct {
+	repoId     string
+	commitHash string
+}
+
+func (c commitFileHistoryController) GetCommitFileHistory() ([]*model.GitCommitFileResult, error) {
+	repoChan := make(chan git.RepoDetails)
+	var repoObject git.RepoInterface
+	repoObject = git.RepoStruct{RepoId: c.repoId}
+	go repoObject.Repo(repoChan)
+	repo := <-repoChan
+
+	repository := middleware.NewRepository(repo.GitRepo)
+
+	fileHistory := commit.NewFileHistory(repository)
+	commitLookup := commit.NewLookup(repository)
+	operation := commit.Operation{FileHistory: fileHistory, Lookup: commitLookup}
+
+	return operation.GitCommitFileHistory(c.commitHash)
+}
+
+func NewCommitFileHistoryController(repoId string, commitHash string) CommitFileHistoryController {
+	return commitFileHistoryController{
+		repoId:     repoId,
+		commitHash: commitHash,
+	}
+}
diff --git a/controller/commit_logs.go b/controller/commit_logs.go
new file mode 100644
index 0000000..be300ba
--- /dev/null
+++ b/controller/commit_logs.go
@@ -0,0 +1,71 @@
+package controller
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type CommitLogController interface {
+	GetCommitLogs() (*model.GitCommitLogResults, error)
+}
+type commitLogController struct {
+	repoId          string
+	referenceCommit string
+}
+
+func (c commitLogController) GetCommitLogs() (*model.GitCommitLogResults, error) {
+	repoChan := make(chan git.RepoDetails)
+	var repoObject git.RepoInterface
+	repoObject = git.RepoStruct{RepoId: c.repoId}
+	go repoObject.Repo(repoChan)
+	repo := <-repoChan
+
+	repository := middleware.NewRepository(repo.GitRepo)
+
+	list := commit.NewListAllLogs(repository, nil, c.referenceId())
+	total := commit.NewTotalCommits(list)
+	fileHistory := commit.NewFileHistory(repository)
+
+	operation := commit.Operation{
+		ListAllLogs: list,
+		Total:       total,
+		FileHistory: fileHistory,
+	}
+
+	commits, err := operation.GitCommitLogs()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return nil, err
+	}
+	totalCommits := operation.GitTotalCommits()
+
+	return &model.GitCommitLogResults{
+		TotalCommits: &totalCommits,
+		Commits:      commits,
+	}, nil
+}
+
+func (c commitLogController) referenceId() *git2go.Oid {
+	if c.referenceCommit == "" {
+		return nil
+	}
+
+	referenceId, oidErr := git2go.NewOid(c.referenceCommit)
+	if oidErr != nil {
+		logger.Log(oidErr.Error(), global.StatusError)
+		return nil
+	}
+
+	return referenceId
+}
+
+func NewCommitLogController(repoId string, referenceCommit string) CommitLogController {
+	return commitLogController{
+		repoId:          repoId,
+		referenceCommit: referenceCommit,
+	}
+}
diff --git a/controller/commit_search_logs.go b/controller/commit_search_logs.go
new file mode 100644
index 0000000..87b85e3
--- /dev/null
+++ b/controller/commit_search_logs.go
@@ -0,0 +1,45 @@
+package controller
+
+import (
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type CommitLogSearchController interface {
+	GetMatchingCommits() ([]*model.GitCommits, error)
+}
+
+type commitLogSearchController struct {
+	repoId     string
+	searchType string
+	searchKey  string
+}
+
+func (c commitLogSearchController) GetMatchingCommits() ([]*model.GitCommits, error) {
+	repoChan := make(chan git.RepoDetails)
+	var repoObject git.RepoInterface
+	repoObject = git.RepoStruct{RepoId: c.repoId}
+	go repoObject.Repo(repoChan)
+	repo := <-repoChan
+
+	repository := middleware.NewRepository(repo.GitRepo)
+
+	list := commit.NewListAllLogs(repository, nil, nil)
+	fileHistory := commit.NewFileHistory(repository)
+	mapper := commit.NewMapper(fileHistory)
+	searchLogs := commit.NewSearchLogs(repository, list, mapper)
+
+	operation := commit.Operation{SearchLogs: searchLogs}
+
+	return operation.GitSearchCommitLogs(c.searchType, c.searchKey)
+}
+
+func NewCommitLogSearchController(repoId string, searchType string, searchKey string) CommitLogSearchController {
+	return commitLogSearchController{
+		repoId:     repoId,
+		searchType: searchType,
+		searchKey:  searchKey,
+	}
+}
diff --git a/controller/controller.go b/controller/controller.go
new file mode 100644
index 0000000..9e6da75
--- /dev/null
+++ b/controller/controller.go
@@ -0,0 +1,5 @@
+package controller
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
diff --git a/controller/remote_controller.go b/controller/remote_controller.go
new file mode 100644
index 0000000..b0b429f
--- /dev/null
+++ b/controller/remote_controller.go
@@ -0,0 +1 @@
+package controller
diff --git a/docker-compose.test.yaml b/docker-compose.test.yaml
new file mode 100644
index 0000000..7d210cd
--- /dev/null
+++ b/docker-compose.test.yaml
@@ -0,0 +1,18 @@
+version: "3.3"
+
+networks:
+  gitconvex-test-network:
+
+services:
+  gitconvex-test:
+    build:
+      context: .
+      dockerfile: Test.Dockerfile
+    environment:
+      - GITCONVEX_TEST_REPO=/home/gitconvex/gitconvex-test
+      - GITCONVEX_DEFAULT_PATH=/home/gitconvex/gitconvex-test
+    networks:
+      - gitconvex-test-network
+    volumes:
+      - ./:/home/gitconvex
+    command: [ "make","test-ci" ]
\ No newline at end of file
diff --git a/generate_all_mocks.sh b/generate_all_mocks.sh
new file mode 100755
index 0000000..813327d
--- /dev/null
+++ b/generate_all_mocks.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Middleware mocks
+mockgen -source=git/middleware/repository.go -destination=mocks/mock_repository.go -package=mocks
+mockgen -source=git/middleware/walk.go -destination=mocks/mock_walk.go -package=mocks
+mockgen -source=git/middleware/reference.go -destination=mocks/mock_reference.go -package=mocks
+mockgen -source=git/middleware/index.go -destination=mocks/mock_index.go -package=mocks
+mockgen -source=git/middleware/branch.go -destination=mocks/mock_branch.go -package=mocks
+mockgen -source=git/middleware/commit.go -destination=mocks/mock_commit.go -package=mocks
+mockgen -source=git/middleware/branch_iterator.go -destination=mocks/mock_branch_iterator.go -package=mocks
+
+# Commit mocks
+mockgen -source=git/commit/git_list_all_commit_logs.go -destination=git/commit/mocks/mock_git_list_all_commit_logs.go -package=mocks
+mockgen -source=git/commit/git_commit_file_history.go -destination=git/commit/mocks/mock_git_commit_file_history.go -package=mocks
+
+# Remote mocks
+mockgen -source=git/remote/remote_validation.go -destination=git/remote/mocks/mock_remote_validation.go -package=mocks
+mockgen -source=git/remote/git_remote_list.go -destination=git/remote/mocks/mock_git_remote_list.go -package=mocks
+mockgen -source=git/middleware/remotes.go -destination=git/remote/mocks/mock_remotes.go -package=mocks
+
+# Branch mocks
+mockgen -source=git/branch/git_branch_add.go  -destination=git/branch/mocks/mock_git_branch_add.go -package=mocks
+
+# Validator mocks
+mockgen -source=validator/validator.go -destination=validator/mocks/mock_validator.go -package=mocks
diff --git a/generators/default_dir_const_gen.go b/generators/default_dir_const_gen.go
new file mode 100644
index 0000000..4de1dff
--- /dev/null
+++ b/generators/default_dir_const_gen.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"text/template"
+)
+
+func main() {
+	templateString := fmt.Sprintf("package global\n\nfunc GetDefaultDirectory() string {\n\treturn \"{{ .DefaultDirFromEnv }}\"\n}\n")
+	var fileTemplate = template.Must(template.New("").Parse(templateString))
+
+	var defaultDirFromEnv = os.Getenv("GITCONVEX_DEFAULT_PATH")
+	file, fileErr := os.Create("./global/default_dir_const.go")
+	if fileErr != nil {
+		log.Fatal(fileErr.Error())
+	}
+
+	err := fileTemplate.ExecuteTemplate(file, "", struct {
+		DefaultDirFromEnv string
+	}{
+		DefaultDirFromEnv: defaultDirFromEnv,
+	})
+	if err != nil {
+		log.Fatal(err.Error())
+	}
+}
diff --git a/git/branch/branch.go b/git/branch/branch.go
new file mode 100644
index 0000000..2e458e5
--- /dev/null
+++ b/git/branch/branch.go
@@ -0,0 +1,5 @@
+package branch
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
diff --git a/git/branch/branch_validation.go b/git/branch/branch_validation.go
new file mode 100644
index 0000000..c3ae663
--- /dev/null
+++ b/git/branch/branch_validation.go
@@ -0,0 +1,37 @@
+package branch
+
+import (
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+type Validation interface {
+	ValidateBranchFields(branchNames ...string) error
+}
+
+type validateBranch struct {
+	repo middleware.Repository
+}
+
+func (v validateBranch) ValidateBranchFields(branchNames ...string) error {
+	if v.repo == nil {
+		return NilRepoError
+	}
+
+	if len(branchNames) == 0 {
+		return EmptyBranchNameError
+	}
+
+	for _, branchName := range branchNames {
+		if branchName == "" {
+			return EmptyBranchNameError
+		}
+	}
+
+	return nil
+}
+
+func NewBranchFieldsValidation(repo middleware.Repository) Validation {
+	return validateBranch{
+		repo: repo,
+	}
+}
diff --git a/git/branch/branch_validation_test.go b/git/branch/branch_validation_test.go
new file mode 100644
index 0000000..7917904
--- /dev/null
+++ b/git/branch/branch_validation_test.go
@@ -0,0 +1,58 @@
+package branch
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type BranchFieldValidationTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	branchNames    []string
+	validation     Validation
+}
+
+func TestBranchFieldValidationTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchFieldValidationTestSuite))
+}
+
+func (suite *BranchFieldValidationTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo)
+}
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenAllFieldsAreValid_ShouldReturnNil() {
+	err := suite.validation.ValidateBranchFields("test_branch_1", "test_branch_2")
+
+	suite.Nil(err)
+}
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenRepoIsNil_ShouldReturnError() {
+	suite.validation = NewBranchFieldsValidation(nil)
+	err := suite.validation.ValidateBranchFields("test_branch_1", "test_branch_2")
+
+	suite.NotNil(err)
+	suite.Equal(NilRepoError, err)
+}
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenBranchNameIsEmpty_ShouldReturnError() {
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo)
+
+	err := suite.validation.ValidateBranchFields()
+
+	suite.NotNil(err)
+	suite.Equal(EmptyBranchNameError, err)
+}
+
+func (suite *BranchFieldValidationTestSuite) TestValidateBranchFields_WhenOneOfBranchNamesIsEmpty_ShouldReturnError() {
+	suite.validation = NewBranchFieldsValidation(suite.mockRepo)
+
+	err := suite.validation.ValidateBranchFields("test_branch_1", "", "test_branch_3")
+
+	suite.NotNil(err)
+	suite.Equal(EmptyBranchNameError, err)
+}
diff --git a/git/branch/checkout/checkout.go b/git/branch/checkout/checkout.go
new file mode 100644
index 0000000..133ad83
--- /dev/null
+++ b/git/branch/checkout/checkout.go
@@ -0,0 +1,17 @@
+package checkout
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
+
+type BranchDetails struct {
+	BranchName          string
+	ReferenceBranchName string
+	RemoteBranchName    string
+}
+
+type Checkout interface {
+	CheckoutBranch() error
+	GenerateBranchFields() BranchDetails
+	LogAndReturnError(err error) error
+}
diff --git a/git/branch/checkout/checkout_factory.go b/git/branch/checkout/checkout_factory.go
new file mode 100644
index 0000000..5f34d04
--- /dev/null
+++ b/git/branch/checkout/checkout_factory.go
@@ -0,0 +1,55 @@
+package checkout
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/validator"
+	"strings"
+)
+
+type Factory interface {
+	GetCheckoutAction(branchName string) Checkout
+}
+
+type factory struct {
+	repo            middleware.Repository
+	repoValidator   validator.Validator
+	branchValidator validator.ValidatorWithStringFields
+}
+
+func (f factory) GetCheckoutAction(branchName string) Checkout {
+	logger.Log(fmt.Sprintf("Received branch %s", branchName), global.StatusInfo)
+	if repoValidationErr := f.repoValidator.Validate(f.repo); repoValidationErr != nil {
+		logger.Log(repoValidationErr.Error(), global.StatusError)
+		return nil
+	}
+
+	if validationErr := f.validateBranchFields(branchName); validationErr != nil {
+		return nil
+	}
+
+	if strings.Contains(branchName, "remotes/") {
+		return NewCheckoutRemoteBranch(f.repo, branchName, nil)
+	} else {
+		return NewCheckOutLocalBranch(f.repo, branchName)
+	}
+}
+
+func (f factory) validateBranchFields(branchName string) error {
+	logger.Log("Validating branch fields before checkout", global.StatusInfo)
+
+	if err := f.branchValidator.ValidateWithFields(branchName); err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+	return nil
+}
+
+func NewCheckoutFactory(repo middleware.Repository, repoValidator validator.Validator, branchValidator validator.ValidatorWithStringFields) Factory {
+	return factory{
+		repo:            repo,
+		repoValidator:   repoValidator,
+		branchValidator: branchValidator,
+	}
+}
diff --git a/git/branch/checkout/checkout_factory_test.go b/git/branch/checkout/checkout_factory_test.go
new file mode 100644
index 0000000..63f47b7
--- /dev/null
+++ b/git/branch/checkout/checkout_factory_test.go
@@ -0,0 +1,85 @@
+package checkout
+
+import (
+	"errors"
+	"github.com/golang/mock/gomock"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	validatorMock "github.com/neel1996/gitconvex/validator/mocks"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type CheckoutFactoryTestSuite struct {
+	suite.Suite
+	repo                middleware.Repository
+	branchName          string
+	remoteBranchName    string
+	mockController      *gomock.Controller
+	mockRepo            *mocks.MockRepository
+	mockBranchValidator *validatorMock.MockValidatorWithStringFields
+	mockRepoValidator   *validatorMock.MockValidator
+	checkoutFactory     Factory
+}
+
+func TestCheckoutFactoryTestSuite(t *testing.T) {
+	suite.Run(t, new(CheckoutFactoryTestSuite))
+}
+
+func (suite *CheckoutFactoryTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranchValidator = validatorMock.NewMockValidatorWithStringFields(suite.mockController)
+	suite.mockRepoValidator = validatorMock.NewMockValidator(suite.mockController)
+	suite.branchName = "test_branch"
+	suite.remoteBranchName = "remotes/origin/test_branch"
+}
+
+func (suite *CheckoutFactoryTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsLocal_ShouldReturnLocalCheckoutAction() {
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
+
+	suite.mockRepoValidator.EXPECT().Validate(suite.mockRepo).Return(nil)
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+
+	wantAction := NewCheckOutLocalBranch(suite.mockRepo, suite.branchName)
+	gotAction := suite.checkoutFactory.GetCheckoutAction(suite.branchName)
+
+	suite.Equal(wantAction, gotAction)
+}
+
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchIsRemote_ShouldReturnRemoteCheckoutAction() {
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
+
+	suite.mockRepoValidator.EXPECT().Validate(suite.mockRepo).Return(nil)
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.remoteBranchName).Return(nil)
+
+	wantAction := NewCheckoutRemoteBranch(suite.mockRepo, suite.remoteBranchName, nil)
+	gotAction := suite.checkoutFactory.GetCheckoutAction(suite.remoteBranchName)
+
+	suite.Equal(wantAction, gotAction)
+}
+
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenRepoValidationFails_ShouldReturnNil() {
+	suite.checkoutFactory = NewCheckoutFactory(nil, suite.mockRepoValidator, suite.mockBranchValidator)
+
+	suite.mockRepoValidator.EXPECT().Validate(nil).Return(validator.NilRepoError)
+	gotAction := suite.checkoutFactory.GetCheckoutAction(suite.branchName)
+
+	suite.Nil(gotAction)
+}
+
+func (suite *CheckoutFactoryTestSuite) TestGetCheckoutAction_WhenBranchValidationFails_ShouldReturnNil() {
+	suite.checkoutFactory = NewCheckoutFactory(suite.mockRepo, suite.mockRepoValidator, suite.mockBranchValidator)
+
+	suite.mockRepoValidator.EXPECT().Validate(suite.mockRepo).Return(nil)
+	suite.mockBranchValidator.EXPECT().ValidateWithFields("").Return(errors.New("VALIDATE_ERROR"))
+
+	gotAction := suite.checkoutFactory.GetCheckoutAction("")
+
+	suite.Nil(gotAction)
+}
diff --git a/git/branch/checkout/checkout_local_branch.go b/git/branch/checkout/checkout_local_branch.go
new file mode 100644
index 0000000..fc983e9
--- /dev/null
+++ b/git/branch/checkout/checkout_local_branch.go
@@ -0,0 +1,73 @@
+package checkout
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type checkOutLocalBranch struct {
+	repo       middleware.Repository
+	branchName string
+}
+
+func (c checkOutLocalBranch) CheckoutBranch() error {
+	repo := c.repo
+	branchName := c.branchName
+
+	logger.Log(fmt.Sprintf("Initiating local branch checkout for %s", branchName), global.StatusInfo)
+
+	branch, branchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
+	if branchErr != nil {
+		return c.LogAndReturnError(branchErr)
+	}
+
+	commit, lookupCommitErr := repo.LookupCommitV2(branch.Target())
+	if lookupCommitErr != nil {
+		return c.LogAndReturnError(lookupCommitErr)
+	}
+
+	tree, treeErr := commit.Tree()
+	if treeErr != nil {
+		return c.LogAndReturnError(treeErr)
+	}
+
+	checkoutErr := repo.CheckoutTree(tree, &git2go.CheckoutOptions{
+		Strategy:       git2go.CheckoutSafe,
+		DisableFilters: false,
+	})
+
+	if checkoutErr != nil {
+		return c.LogAndReturnError(checkoutErr)
+	}
+
+	err := repo.SetHead(c.GenerateBranchFields().ReferenceBranchName)
+	if err != nil {
+		return c.LogAndReturnError(err)
+	}
+
+	logger.Log(fmt.Sprintf("Local branch %v has been checked out", c.branchName), global.StatusInfo)
+	return nil
+}
+
+func (c checkOutLocalBranch) GenerateBranchFields() BranchDetails {
+	referenceBranchName := "refs/heads/" + c.branchName
+
+	return BranchDetails{
+		BranchName:          c.branchName,
+		ReferenceBranchName: referenceBranchName,
+	}
+}
+
+func (c checkOutLocalBranch) LogAndReturnError(err error) error {
+	logger.Log(err.Error(), global.StatusError)
+	return err
+}
+
+func NewCheckOutLocalBranch(repo middleware.Repository, branchName string) Checkout {
+	return checkOutLocalBranch{
+		repo:       repo,
+		branchName: branchName,
+	}
+}
diff --git a/git/branch/checkout/checkout_local_branch_test.go b/git/branch/checkout/checkout_local_branch_test.go
new file mode 100644
index 0000000..8ab094c
--- /dev/null
+++ b/git/branch/checkout/checkout_local_branch_test.go
@@ -0,0 +1,124 @@
+package checkout
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/test_utils"
+	"github.com/neel1996/gitconvex/validator"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CheckOutLocalBranchTestSuite struct {
+	suite.Suite
+	repo                middleware.Repository
+	mockController      *gomock.Controller
+	mockRepo            *mocks.MockRepository
+	mockBranch          *mocks.MockBranch
+	mockCommit          *mocks.MockCommit
+	branchName          string
+	checkOutLocalBranch Checkout
+}
+
+func TestCheckOutLocalBranchTestSuite(t *testing.T) {
+	suite.Run(t, new(CheckOutLocalBranchTestSuite))
+}
+
+func (suite *CheckOutLocalBranchTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchName = "test_checkout"
+
+	test_utils.AddNewTestLocalBranch(suite.repo, suite.branchName)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TearDownSuite() {
+	_ = branch.NewDeleteBranch(suite.repo, validator.NewBranchValidator()).DeleteBranch(suite.branchName)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+
+	suite.checkOutLocalBranch = NewCheckOutLocalBranch(suite.mockRepo, suite.branchName)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid_ShouldCheckoutLocalBranch() {
+	suite.checkOutLocalBranch = NewCheckOutLocalBranch(suite.repo, suite.branchName)
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenBranchLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCommitLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(errors.New("TREE_CHECKOUT_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutLocalBranchTestSuite) TestCheckoutBranch_WhenSetHeadFails_ShouldReturnError() {
+	referenceName := "refs/heads/" + suite.branchName
+
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().SetHead(referenceName).Return(errors.New("SET_HEAD_ERROR"))
+
+	err := suite.checkOutLocalBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
diff --git a/git/branch/checkout/checkout_remote_branch.go b/git/branch/checkout/checkout_remote_branch.go
new file mode 100644
index 0000000..2f0ace3
--- /dev/null
+++ b/git/branch/checkout/checkout_remote_branch.go
@@ -0,0 +1,108 @@
+package checkout
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"strings"
+)
+
+type checkOutRemoteBranch struct {
+	repo       middleware.Repository
+	branchName string
+	addBranch  branch.Add
+}
+
+func (c checkOutRemoteBranch) CheckoutBranch() error {
+	repo := c.repo
+	branchName := c.branchName
+
+	logger.Log(fmt.Sprintf("Initiating remote branch checkout for %s", branchName), global.StatusInfo)
+
+	branchFields := c.GenerateBranchFields()
+
+	logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
+	remoteBranch, remoteBranchErr := repo.LookupBranch(branchFields.RemoteBranchName, git2go.BranchRemote)
+	if remoteBranchErr != nil {
+		return c.LogAndReturnError(remoteBranchErr)
+	}
+
+	remoteHead := remoteBranch.Target()
+	remoteCommit, remoteCommitErr := repo.LookupCommitV2(remoteHead)
+	if remoteCommitErr != nil {
+		return c.LogAndReturnError(remoteCommitErr)
+
+	}
+
+	remoteTree, remoteTreeErr := remoteCommit.Tree()
+	if remoteTreeErr != nil {
+		return c.LogAndReturnError(remoteTreeErr)
+	}
+
+	if checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe}); checkoutErr != nil {
+		return c.LogAndReturnError(checkoutErr)
+	}
+
+	_, localLookupErr := repo.LookupBranch(branchFields.BranchName, git2go.BranchLocal)
+	if localLookupErr != nil {
+		logger.Log(localLookupErr.Error(), global.StatusError)
+		gitCommit := remoteCommit.GetGitCommit()
+		return c.addAndCheckoutNewBranch(gitCommit, branchFields.ReferenceBranchName)
+	}
+
+	if err := repo.SetHead(branchFields.ReferenceBranchName); err != nil {
+		return c.LogAndReturnError(err)
+	}
+
+	logger.Log(fmt.Sprintf("Remote branch %v has been checked out", branchFields.RemoteBranchName), global.StatusInfo)
+
+	return nil
+}
+
+func (c checkOutRemoteBranch) addAndCheckoutNewBranch(remoteCommit *git2go.Commit, referenceBranchName string) error {
+	logger.Log("Adding local branch for remote reference", global.StatusInfo)
+
+	branchAddError := c.addBranch.AddBranch(c.branchName, false, remoteCommit)
+	if branchAddError != nil {
+		logger.Log("Error while adding branch "+branchAddError.Error(), global.StatusError)
+		return branchAddError
+	}
+
+	if err := c.repo.SetHead(referenceBranchName); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (c checkOutRemoteBranch) GenerateBranchFields() BranchDetails {
+	referenceBranchName := "refs/heads/" + c.splitAndReturnBranchName("/", c.branchName)
+	remoteBranchName := c.splitAndReturnBranchName("remotes/", c.branchName)
+	branchName := c.splitAndReturnBranchName("/", c.branchName)
+
+	return BranchDetails{
+		BranchName:          branchName,
+		ReferenceBranchName: referenceBranchName,
+		RemoteBranchName:    remoteBranchName,
+	}
+}
+
+func (c checkOutRemoteBranch) LogAndReturnError(err error) error {
+	logger.Log(err.Error(), global.StatusError)
+	return err
+}
+
+func (c checkOutRemoteBranch) splitAndReturnBranchName(delimiter string, branchName string) string {
+	splitString := strings.Split(branchName, delimiter)
+	return splitString[len(splitString)-1]
+}
+
+func NewCheckoutRemoteBranch(repo middleware.Repository, branchName string, addBranch branch.Add) Checkout {
+	return checkOutRemoteBranch{
+		repo:       repo,
+		branchName: branchName,
+		addBranch:  addBranch,
+	}
+}
diff --git a/git/branch/checkout/checkout_remote_branch_test.go b/git/branch/checkout/checkout_remote_branch_test.go
new file mode 100644
index 0000000..735d0e4
--- /dev/null
+++ b/git/branch/checkout/checkout_remote_branch_test.go
@@ -0,0 +1,184 @@
+package checkout
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch"
+	branchMocks "github.com/neel1996/gitconvex/git/branch/mocks"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CheckOutRemoteBranchTestSuite struct {
+	suite.Suite
+	repo                     middleware.Repository
+	mockController           *gomock.Controller
+	mockRepo                 *mocks.MockRepository
+	mockBranch               *mocks.MockBranch
+	mockCommit               *mocks.MockCommit
+	branchName               string
+	remoteBranchName         string
+	localBranchName          string
+	localBranchReferenceName string
+	branchValidation         validator.ValidatorWithStringFields
+	addBranch                branch.Add
+	mockValidation           *branchMocks.MockValidation
+	mockAddBranch            *branchMocks.MockAdd
+	checkOutRemoteBranch     Checkout
+}
+
+func TestCheckOutRemoteBranchTestSuite(t *testing.T) {
+	suite.Run(t, new(CheckOutRemoteBranchTestSuite))
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchName = "remotes/origin/test_remote"
+	suite.remoteBranchName = "origin/test_remote"
+	suite.localBranchName = "test_remote"
+	suite.localBranchReferenceName = "refs/heads/test_remote"
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.mockValidation = branchMocks.NewMockValidation(suite.mockController)
+	suite.mockAddBranch = branchMocks.NewMockAdd(suite.mockController)
+	suite.branchValidation = validator.NewBranchValidator()
+	suite.addBranch = branch.NewAddBranch(suite.repo, suite.branchValidation)
+
+	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.mockRepo, suite.branchName, suite.mockAddBranch)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchIsValid_ShouldCheckoutLocalBranch() {
+	suite.checkOutRemoteBranch = NewCheckoutRemoteBranch(suite.repo, suite.branchName, branch.NewAddBranch(suite.repo, validator.NewBranchValidator()))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenBranchLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCommitLookupFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenFetchCommitTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenCheckoutTreeFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(errors.New("TREE_CHECKOUT_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLookupLocalBranchFails_ShouldAddNewLocalBranch() {
+	gitCommit := &git2go.Commit{}
+
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
+	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(nil)
+	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(nil)
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.Nil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenLocalAddBranchFails_ShouldReturnError() {
+	gitCommit := &git2go.Commit{}
+
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
+	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(errors.New("ADD_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFailsAfterAddingNewBranch_ShouldReturnError() {
+	gitCommit := &git2go.Commit{}
+
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+	suite.mockCommit.EXPECT().GetGitCommit().Return(gitCommit)
+	suite.mockAddBranch.EXPECT().AddBranch(suite.branchName, false, gitCommit).Return(nil)
+	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(errors.New("SET_HEAD_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
+
+func (suite *CheckOutRemoteBranchTestSuite) TestCheckoutBranch_WhenSetHeadFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().LookupBranch(suite.remoteBranchName, git2go.BranchRemote).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Target().Return(&git2go.Oid{})
+	suite.mockRepo.EXPECT().LookupCommitV2(gomock.Any()).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().Tree().Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CheckoutTree(gomock.Any(), gomock.Any()).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.localBranchName, git2go.BranchLocal).Return(nil, nil)
+	suite.mockRepo.EXPECT().SetHead(suite.localBranchReferenceName).Return(errors.New("SET_HEAD_ERROR"))
+
+	err := suite.checkOutRemoteBranch.CheckoutBranch()
+
+	suite.NotNil(err)
+}
diff --git a/git/branch/errors.go b/git/branch/errors.go
new file mode 100644
index 0000000..2f72403
--- /dev/null
+++ b/git/branch/errors.go
@@ -0,0 +1,19 @@
+package branch
+
+type Error struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	NilRepoError         = Error{ErrorCode: "REPO_NIL_ERROR", ErrorString: "Repo is nil"}
+	EmptyBranchNameError = Error{ErrorCode: "BRANCH_EMPTY_ERROR", ErrorString: "Branch name(s) is empty"}
+	LookupError          = Error{ErrorCode: "BRANCH_LOOKUP_ERROR", ErrorString: "Branch lookup Failed"}
+	CompareError         = Error{ErrorCode: "BRANCH_COMPARE_ERROR", ErrorString: "Comparing the two branches returned no difference"}
+	NilHeadError         = Error{ErrorCode: "REPO_HEAD_ERROR", ErrorString: "Can not fetch repo HEAD"}
+)
+
+func (e Error) Error() string {
+	return e.ErrorString
+}
diff --git a/git/branch/git_branch_add.go b/git/branch/git_branch_add.go
new file mode 100644
index 0000000..f24e543
--- /dev/null
+++ b/git/branch/git_branch_add.go
@@ -0,0 +1,86 @@
+package branch
+
+//go:generate git/branch/git_branch_add.go
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/validator"
+)
+
+type Add interface {
+	AddBranch(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error
+}
+
+type addBranch struct {
+	repo             middleware.Repository
+	branchName       string
+	remoteSwitch     bool
+	targetCommit     *git2go.Commit
+	branchValidation validator.ValidatorWithStringFields
+}
+
+func (a addBranch) AddBranch(branchName string, remoteSwitch bool, targetCommit *git2go.Commit) error {
+	a.branchName = branchName
+	a.remoteSwitch = remoteSwitch
+	a.targetCommit = targetCommit
+
+	err := a.validateAddBranchFields()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+
+	head, headErr := a.repo.Head()
+	if headErr != nil {
+		logger.Log(fmt.Sprintf("Unable to fetch HEAD -> %s", headErr.Error()), global.StatusError)
+		return headErr
+	}
+
+	targetCommit, validationErr := a.validateTargetCommit(a.targetCommit, a.repo, head)
+	if validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
+	}
+
+	logger.Log(fmt.Sprintf("Adding new branch -> %s", a.branchName), global.StatusInfo)
+
+	_, branchErr := a.repo.CreateBranch(a.branchName, targetCommit, false)
+	if branchErr != nil {
+		logger.Log(fmt.Sprintf("Failed to add branch - %s - %s", a.branchName, branchErr.Error()), global.StatusError)
+		return branchErr
+	}
+
+	logger.Log(fmt.Sprintf("Added new branch - %s to the repo", a.branchName), global.StatusInfo)
+	return nil
+}
+
+func (a addBranch) validateAddBranchFields() error {
+	err := a.branchValidation.ValidateWithFields(a.branchName)
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo middleware.Repository, head middleware.Reference) (*git2go.Commit, error) {
+	if targetCommit != nil {
+		return targetCommit, nil
+	}
+
+	headCommit, headCommitErr := repo.LookupCommit(head.Target())
+	if headCommit == nil {
+		return nil, headCommitErr
+	}
+
+	return headCommit, nil
+}
+
+func NewAddBranch(repo middleware.Repository, branchValidation validator.ValidatorWithStringFields) Add {
+	return addBranch{
+		repo:             repo,
+		branchValidation: branchValidation,
+	}
+}
diff --git a/git/branch/git_branch_add_test.go b/git/branch/git_branch_add_test.go
new file mode 100644
index 0000000..98cfaf1
--- /dev/null
+++ b/git/branch/git_branch_add_test.go
@@ -0,0 +1,117 @@
+package branch
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	"github.com/google/uuid"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	validatorMock "github.com/neel1996/gitconvex/validator/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type BranchAddTestSuite struct {
+	suite.Suite
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockReference        *mocks.MockReference
+	mockBranchValidation *validatorMock.MockValidatorWithStringFields
+	mockCommit           *mocks.MockCommit
+	branchName           string
+	branchValidation     validator.ValidatorWithStringFields
+	branchAdd            Add
+}
+
+func TestBranchAddTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchAddTestSuite))
+}
+
+func (suite *BranchAddTestSuite) SetupSuite() {
+	suite.branchName = uuid.New().String()
+}
+
+func (suite *BranchAddTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchValidation = validator.NewBranchValidator()
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.mockBranchValidation = validatorMock.NewMockValidatorWithStringFields(suite.mockController)
+
+	suite.branchAdd = NewAddBranch(suite.mockRepo, suite.mockBranchValidation)
+}
+
+func (suite *BranchAddTestSuite) TearDownSuite() {
+	_ = NewDeleteBranch(suite.repo, validator.NewBranchValidator()).DeleteBranch(suite.branchName)
+	suite.mockController.Finish()
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchAdditionSucceeds_ShouldReturnNil() {
+	suite.branchAdd = NewAddBranch(suite.repo, suite.branchValidation)
+
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
+
+	suite.Nil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenBranchValidationFails_ShouldReturnError() {
+	suite.mockBranchValidation.EXPECT().ValidateWithFields("").Return(EmptyBranchNameError)
+
+	branchAddError := suite.branchAdd.AddBranch("", false, nil)
+
+	suite.NotNil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadIsNil_ShouldReturnError() {
+	suite.mockBranchValidation.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERROR"))
+
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
+
+	suite.NotNil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenHeadCommitLookupFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("0608f9c6c97f386d1fa3948f3b8a61ae1cdb5621")
+
+	suite.mockBranchValidation.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
+
+	suite.NotNil(branchAddError)
+}
+
+func (suite *BranchAddTestSuite) TestAddBranch_WhenCreateBranchFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("0608f9c6c97f386d1fa3948f3b8a61ae1cdb5621")
+	commit := &git2go.Commit{}
+
+	suite.mockBranchValidation.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(commit, nil)
+	suite.mockRepo.EXPECT().CreateBranch(
+		suite.branchName,
+		commit,
+		false,
+	).Return(nil, errors.New("BRANCH_CREATE_ERROR"))
+
+	branchAddError := suite.branchAdd.AddBranch(suite.branchName, false, nil)
+
+	suite.NotNil(branchAddError)
+}
diff --git a/git/branch/git_branch_compare.go b/git/branch/git_branch_compare.go
new file mode 100644
index 0000000..22aa55e
--- /dev/null
+++ b/git/branch/git_branch_compare.go
@@ -0,0 +1,218 @@
+package branch
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/validator"
+	"sort"
+	"strings"
+)
+
+type Compare interface {
+	CompareBranch(baseBranchName string, diffBranchName string) ([]*model.BranchCompareResults, error)
+}
+
+type branchCompare struct {
+	repo            middleware.Repository
+	branchValidator validator.ValidatorWithStringFields
+}
+
+func logAndReturnError(err error) ([]*model.BranchCompareResults, error) {
+	logger.Log(err.Error(), global.StatusError)
+	return []*model.BranchCompareResults{}, err
+}
+
+// CompareBranch compares two branches and returns the commits which are different from each other
+// The function uses the git client to fetch the results as go-git lacks this feature
+func (b branchCompare) CompareBranch(baseBranchName string, diffBranchName string) ([]*model.BranchCompareResults, error) {
+	var diffCommits []*model.BranchCompareResults
+	var filteredCommits []model.GitCommits
+
+	if validationErr := b.branchValidator.ValidateWithFields(baseBranchName, diffBranchName); validationErr != nil {
+		return logAndReturnError(validationErr)
+	}
+
+	baseBranch, compareBranch, lookupErr := b.lookupBranch(baseBranchName, diffBranchName)
+	if lookupErr != nil {
+		return logAndReturnError(LookupError)
+	}
+
+	compareResult := baseBranch.Cmp(compareBranch.Reference())
+	if compareResult == 0 {
+		return logAndReturnError(CompareError)
+	}
+
+	baseHeadCommit, compareHeadCommit, headCommitErr := b.getHeadCommits(baseBranch, compareBranch)
+	if headCommitErr != nil {
+		return logAndReturnError(NilHeadError)
+	}
+
+	baseBranchCommits, compareBranchCommits := b.getAncestorsOf(baseHeadCommit, compareHeadCommit)
+
+	filteredCommits = filterDifferingCommits(compareBranchCommits, baseBranchCommits)
+	commitMap := generateCommitMap(filteredCommits)
+	diffCommits = sortCommitsInDescendingOrderOfDate(commitMap, diffCommits)
+
+	return diffCommits, nil
+}
+
+func (b branchCompare) lookupBranch(baseBranchName string, diffBranchName string) (middleware.Branch, middleware.Branch, error) {
+	var (
+		baseBranchErr    error
+		compareBranchErr error
+	)
+
+	baseBranch, baseBranchErr := b.repo.LookupBranch(baseBranchName, git2go.BranchLocal)
+
+	if baseBranchErr != nil {
+		logger.Log(baseBranchErr.Error(), global.StatusError)
+		return nil, nil, baseBranchErr
+	}
+
+	compareBranch, compareBranchErr := b.repo.LookupBranch(diffBranchName, git2go.BranchLocal)
+	if compareBranchErr != nil {
+		logger.Log(compareBranchErr.Error(), global.StatusError)
+		return nil, nil, compareBranchErr
+	}
+
+	return baseBranch, compareBranch, nil
+}
+
+func (b branchCompare) getHeadCommits(baseBranch middleware.Branch, compareBranch middleware.Branch) (middleware.Commit, middleware.Commit, error) {
+	var (
+		baseHeadErr    error
+		compareHeadErr error
+	)
+
+	baseTarget := baseBranch.Target()
+	baseHead, baseHeadErr := b.repo.LookupCommitV2(baseTarget)
+	if baseHeadErr != nil {
+		logger.Log(baseHeadErr.Error(), global.StatusError)
+		return nil, nil, baseHeadErr
+	}
+
+	compareTarget := compareBranch.Target()
+	compareHead, compareHeadErr := b.repo.LookupCommitV2(compareTarget)
+	if compareHeadErr != nil {
+		logger.Log(compareHeadErr.Error(), global.StatusError)
+		return nil, nil, compareHeadErr
+	}
+
+	return baseHead, compareHead, nil
+}
+
+func (b branchCompare) getAncestorsOf(baseHead middleware.Commit, compareHead middleware.Commit) (map[string]middleware.Commit, map[string]middleware.Commit) {
+	baseBranchMap := getParentCommitsOf(baseHead)
+	compareBranchMap := getParentCommitsOf(compareHead)
+
+	return baseBranchMap, compareBranchMap
+}
+
+// Organizing differing commits based on date
+func generateCommitMap(filteredCommits []model.GitCommits) map[string][]*model.GitCommits {
+	var commitMap = make(map[string][]*model.GitCommits)
+	var commitHashMap = make(map[string]bool)
+
+	for i := range filteredCommits {
+		selectedDate := *filteredCommits[i].CommitTime
+
+		j := i
+		for j < len(filteredCommits) {
+			if isCommitDateNotTheSelectedDate(selectedDate, filteredCommits, j) && isCommitHashAlreadyInTheList(commitHashMap, filteredCommits, j) {
+				break
+			}
+
+			if commitMap[selectedDate] != nil {
+				tempCommit := commitMap[selectedDate]
+				tempCommit = append(tempCommit, &filteredCommits[j])
+				commitMap[selectedDate] = tempCommit
+				commitHashMap[*filteredCommits[j].Hash] = true
+			} else {
+				tempCommit := []*model.GitCommits{&filteredCommits[j]}
+				commitMap[selectedDate] = tempCommit
+				commitHashMap[*filteredCommits[j].Hash] = true
+			}
+			j++
+		}
+	}
+	return commitMap
+}
+
+func isCommitDateNotTheSelectedDate(selectedDate string, filteredCommits []model.GitCommits, iterator int) bool {
+	if selectedDate != *filteredCommits[iterator].CommitTime {
+		return true
+	}
+
+	return false
+}
+
+func isCommitHashAlreadyInTheList(commitHashMap map[string]bool, filteredCommits []model.GitCommits, iterator int) bool {
+	if len(commitHashMap) > 0 && commitHashMap[*filteredCommits[iterator].Hash] {
+		return true
+	}
+
+	return false
+}
+
+func filterDifferingCommits(compareBranchMap map[string]middleware.Commit, baseBranchMap map[string]middleware.Commit) []model.GitCommits {
+	var commits []model.GitCommits
+	for commitHash, commit := range compareBranchMap {
+		if baseBranchMap[commitHash] == nil {
+			hash := commit.Id().String()
+			author := commit.Author().Name
+			commitTime := strings.Split(commit.Author().When.String(), " ")[0]
+			message := commit.Message()
+
+			commits = append(commits, model.GitCommits{
+				Hash:          &hash,
+				Author:        &author,
+				CommitTime:    &commitTime,
+				CommitMessage: &message,
+			})
+		}
+	}
+	return commits
+}
+
+func getParentCommitsOf(head middleware.Commit) map[string]middleware.Commit {
+	var next middleware.Commit
+	commitMap := make(map[string]middleware.Commit)
+
+	if head.ParentCount() == 0 {
+		return commitMap
+	}
+
+	next = head.Parent(0)
+	for next != nil {
+		commitMap[next.Id().String()] = next
+		next = next.Parent(0)
+	}
+
+	return commitMap
+}
+
+func sortCommitsInDescendingOrderOfDate(commitMap map[string][]*model.GitCommits, diffCommits []*model.BranchCompareResults) []*model.BranchCompareResults {
+	var keys []string
+	for k := range commitMap {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	sort.Sort(sort.Reverse(sort.StringSlice(keys)))
+
+	for _, date := range keys {
+		diffCommits = append(diffCommits, &model.BranchCompareResults{
+			Date:    date,
+			Commits: commitMap[date],
+		})
+	}
+	return diffCommits
+}
+
+func NewBranchCompare(repo middleware.Repository, branchValidator validator.ValidatorWithStringFields) Compare {
+	return branchCompare{
+		repo:            repo,
+		branchValidator: branchValidator,
+	}
+}
diff --git a/git/branch/git_branch_compare_test.go b/git/branch/git_branch_compare_test.go
new file mode 100644
index 0000000..c9c7235
--- /dev/null
+++ b/git/branch/git_branch_compare_test.go
@@ -0,0 +1,189 @@
+package branch
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	mocks2 "github.com/neel1996/gitconvex/validator/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+type BranchCompareTestSuite struct {
+	suite.Suite
+	branchCompare       Compare
+	branchValidator     validator.ValidatorWithStringFields
+	repo                middleware.Repository
+	mockController      *gomock.Controller
+	mockRepo            *mocks.MockRepository
+	mockBranchValidator *mocks2.MockValidatorWithStringFields
+	mockBranch          *mocks.MockBranch
+	mockReference       *mocks.MockReference
+	mockCommit          *mocks.MockCommit
+	baseBranch          string
+	compareBranch       string
+	testFile            string
+}
+
+func TestBranchCompareTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchCompareTestSuite))
+}
+
+func (suite *BranchCompareTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchValidator = validator.NewBranchValidator()
+	suite.testFile = os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "compare_test.txt"
+	suite.compareBranch = "new_compare"
+
+	addErr := NewAddBranch(middleware.NewRepository(r), validator.NewBranchValidator()).AddBranch(suite.compareBranch, false, nil)
+	if addErr != nil {
+		fmt.Println(addErr)
+	}
+
+	test_utils.StageAndCommitTestFile(suite.repo, suite.compareBranch, suite.testFile)
+}
+
+func (suite *BranchCompareTestSuite) SetupTest() {
+	suite.baseBranch = "master"
+	suite.compareBranch = "new_compare"
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.mockBranchValidator = mocks2.NewMockValidatorWithStringFields(suite.mockController)
+
+	suite.branchCompare = NewBranchCompare(suite.mockRepo, suite.mockBranchValidator)
+}
+
+func (suite *BranchCompareTestSuite) TearDownSuite() {
+	test_utils.CheckoutTestBranch(suite.repo, suite.baseBranch)
+
+	err := os.Remove(suite.testFile)
+	if err != nil {
+		return
+	}
+	test_utils.DeleteTestBranch(suite.repo, suite.compareBranch)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchesHaveDifferentCommits_ShouldReturnDifference() {
+	suite.branchCompare = NewBranchCompare(suite.repo, suite.branchValidator)
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.Nil(err)
+	suite.NotNil(compareResults)
+	suite.NotZero(len(compareResults))
+	suite.NotZero(len(compareResults[0].Commits))
+
+	suite.NotNil(*compareResults[0].Commits[0])
+	suite.NotEmpty(*compareResults[0].Commits[0].CommitMessage)
+	suite.NotEmpty(compareResults[0].Date)
+	suite.GreaterOrEqual(len(compareResults[0].Commits), 1)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchValidationFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, "").Return(errors.New("VALIDATION_ERR"))
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, "")
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBaseBranchLookupFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenDiffBranchLookupFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenBranchCompareReturnsZero_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(0)
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenCommitLookupForBaseBranchFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("591ee574417890b6771d8c314d6f116586414e29")
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(1)
+	suite.mockBranch.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenCommitLookupForCompareBranchFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("591ee574417890b6771d8c314d6f116586414e29")
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(1)
+	suite.mockBranch.EXPECT().Target().Return(oid).MaxTimes(2)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(suite.mockCommit, nil)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.NotNil(err)
+	suite.Len(compareResults, 0)
+}
+
+func (suite *BranchCompareTestSuite) TestCompareBranch_WhenParentCountOfCommitsIsZero_ShouldReturnEmptyResults() {
+	oid, _ := git2go.NewOid("591ee574417890b6771d8c314d6f116586414e29")
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.baseBranch, suite.compareBranch).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.baseBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.compareBranch, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Reference().Return(suite.mockReference)
+	suite.mockBranch.EXPECT().Cmp(suite.mockReference).Return(1)
+	suite.mockBranch.EXPECT().Target().Return(oid).MaxTimes(2)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(suite.mockCommit, nil)
+	suite.mockRepo.EXPECT().LookupCommitV2(oid).Return(suite.mockCommit, nil)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(0)).Times(2)
+
+	compareResults, err := suite.branchCompare.CompareBranch(suite.baseBranch, suite.compareBranch)
+
+	suite.Nil(err)
+	suite.Len(compareResults, 0)
+}
diff --git a/git/branch/git_branch_delete.go b/git/branch/git_branch_delete.go
new file mode 100644
index 0000000..be4c8cc
--- /dev/null
+++ b/git/branch/git_branch_delete.go
@@ -0,0 +1,50 @@
+package branch
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/validator"
+)
+
+type Delete interface {
+	DeleteBranch(branchName string) error
+}
+
+type deleteBranch struct {
+	repo            middleware.Repository
+	branchValidator validator.ValidatorWithStringFields
+}
+
+func (d deleteBranch) DeleteBranch(branchName string) error {
+	repo := d.repo
+
+	validationErr := d.branchValidator.ValidateWithFields(branchName)
+	if validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
+	}
+
+	branch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
+	if deleteBranchErr != nil {
+		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteBranchErr.Error()), global.StatusError)
+		return deleteBranchErr
+	}
+
+	deleteErr := branch.Delete()
+	if deleteErr != nil {
+		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteErr.Error()), global.StatusError)
+		return deleteErr
+	}
+
+	logger.Log(fmt.Sprintf("Branch - %s has been removed from the repo", branchName), global.StatusInfo)
+	return nil
+}
+
+func NewDeleteBranch(repo middleware.Repository, branchValidator validator.ValidatorWithStringFields) Delete {
+	return deleteBranch{
+		repo:            repo,
+		branchValidator: branchValidator,
+	}
+}
diff --git a/git/branch/git_branch_delete_test.go b/git/branch/git_branch_delete_test.go
new file mode 100644
index 0000000..f79abf3
--- /dev/null
+++ b/git/branch/git_branch_delete_test.go
@@ -0,0 +1,96 @@
+package branch
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/neel1996/gitconvex/validator"
+	mocks2 "github.com/neel1996/gitconvex/validator/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type BranchDeleteTestSuite struct {
+	suite.Suite
+	mockController      *gomock.Controller
+	branchDelete        Delete
+	branchName          string
+	repo                middleware.Repository
+	mockBranch          *mocks.MockBranch
+	branchValidator     validator.ValidatorWithStringFields
+	mockRepo            *mocks.MockRepository
+	mockBranchValidator *mocks2.MockValidatorWithStringFields
+}
+
+func TestBranchDeleteTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchDeleteTestSuite))
+}
+
+func (suite *BranchDeleteTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.branchName = "delete_branch"
+
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockBranchValidator = mocks2.NewMockValidatorWithStringFields(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+
+	suite.branchDelete = NewDeleteBranch(suite.mockRepo, suite.mockBranchValidator)
+}
+
+func (suite *BranchDeleteTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.branchValidator = validator.NewBranchValidator()
+	suite.branchName = "delete_branch"
+	addErr := NewAddBranch(suite.repo, validator.NewBranchValidator()).AddBranch(suite.branchName, false, nil)
+	if addErr != nil {
+		fmt.Println(addErr)
+	}
+}
+
+func (suite *BranchDeleteTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchIsDeleted_ShouldReturnNil() {
+	suite.branchDelete = NewDeleteBranch(suite.repo, suite.branchValidator)
+
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
+
+	suite.Nil(err)
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenValidationFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(errors.New("VALIDATION_ERROR"))
+
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchLookupFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(nil, errors.New("LOOKUP_ERR"))
+
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchDeleteTestSuite) TestDeleteBranch_WhenBranchDeleteFails_ShouldReturnError() {
+	suite.mockBranchValidator.EXPECT().ValidateWithFields(suite.branchName).Return(nil)
+	suite.mockRepo.EXPECT().LookupBranch(suite.branchName, git2go.BranchLocal).Return(suite.mockBranch, nil)
+	suite.mockBranch.EXPECT().Delete().Return(errors.New("DELETE_ERROR"))
+
+	err := suite.branchDelete.DeleteBranch(suite.branchName)
+
+	suite.NotNil(err)
+}
diff --git a/git/branch/git_branch_list.go b/git/branch/git_branch_list.go
new file mode 100644
index 0000000..1d7f7a6
--- /dev/null
+++ b/git/branch/git_branch_list.go
@@ -0,0 +1,132 @@
+package branch
+
+import (
+	"errors"
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+	"strings"
+)
+
+type List interface {
+	ListBranches() (model.ListOfBranches, error)
+}
+
+type listBranch struct {
+	repo middleware.Repository
+}
+
+type branches struct {
+	localBranchList  []string
+	remoteBranchList []string
+	combinedBranches []string
+}
+
+func (l listBranch) ListBranches() (model.ListOfBranches, error) {
+	var (
+		currentBranch   string
+		localBranchList []string
+		allBranchList   []string
+	)
+	repo := l.repo
+
+	head, headErr := repo.Head()
+	if headErr != nil {
+		logger.Log(fmt.Sprintf("Repo head is invalid -> %s", headErr.Error()), global.StatusError)
+		return model.ListOfBranches{}, headErr
+	}
+
+	currentBranch = getCurrentBranchName(head)
+
+	allBranchList = append(allBranchList, currentBranch)
+	localBranchList = append(localBranchList, currentBranch)
+
+	localBranchIterator, itrErr := repo.NewBranchIterator(git2go.BranchAll)
+	if itrErr != nil {
+		logger.Log(itrErr.Error(), global.StatusError)
+		return model.ListOfBranches{}, itrErr
+	}
+
+	allBranches, err := l.getAllBranches(localBranchIterator, currentBranch)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return model.ListOfBranches{}, err
+	}
+
+	allBranchList = append(allBranchList, allBranches.combinedBranches...)
+	localBranchList = append(localBranchList, allBranches.localBranchList...)
+
+	return model.ListOfBranches{
+		CurrentBranch: currentBranch,
+		BranchList:    localBranchList,
+		AllBranchList: allBranchList,
+	}, nil
+}
+
+func (l listBranch) getAllBranches(localBranchIterator middleware.BranchIterator, currentBranch string) (branches, error) {
+	var (
+		localBranches  []string
+		remoteBranches []string
+	)
+
+	err := localBranchIterator.ForEach(func(b *git2go.Branch, branchType git2go.BranchType) error {
+		branch := middleware.NewBranch(b)
+		branchName, nameErr := branch.Name()
+		if nameErr != nil {
+			return nameErr
+		}
+
+		if branch.IsTag() || branch.IsNote() || branchName == currentBranch {
+			return nil
+		}
+
+		if branch.IsRemote() {
+			prefixedRemoteBranchName, err := l.getPrefixedRemoteBranch(branchName, currentBranch)
+			if err == nil {
+				remoteBranches = append(remoteBranches, prefixedRemoteBranchName)
+			}
+		} else {
+			localBranches = append(localBranches, branchName)
+		}
+
+		return nil
+	})
+
+	return branches{
+		localBranchList:  localBranches,
+		remoteBranchList: remoteBranches,
+		combinedBranches: append(localBranches, remoteBranches...),
+	}, err
+}
+
+func (l listBranch) getPrefixedRemoteBranch(branchName string, currentBranch string) (string, error) {
+	shortBranchName := l.getShortBranchName(branchName)
+
+	if shortBranchName != "HEAD" && shortBranchName != currentBranch {
+		remoteBranchName := "remotes/" + branchName
+		return remoteBranchName, nil
+	}
+	return "", errors.New("invalid remote branch")
+}
+
+func (l listBranch) getShortBranchName(b string) string {
+	str := strings.Split(b, "/")
+	branchName := str[len(str)-1]
+
+	return branchName
+}
+
+func getCurrentBranchName(head middleware.Reference) string {
+	branch := head.Name()
+	splitCurrentBranch := strings.Split(branch, "/")
+	branch = splitCurrentBranch[len(splitCurrentBranch)-1]
+	return branch
+}
+
+func NewBranchList(repo middleware.Repository) List {
+	return listBranch{
+		repo: repo,
+	}
+}
diff --git a/git/branch/git_branch_list_test.go b/git/branch/git_branch_list_test.go
new file mode 100644
index 0000000..9d836f9
--- /dev/null
+++ b/git/branch/git_branch_list_test.go
@@ -0,0 +1,93 @@
+package branch
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/branch/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"log"
+	"os"
+	"testing"
+)
+
+type BranchListTestSuite struct {
+	suite.Suite
+	repo           middleware.Repository
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	mockReference  *mocks.MockReference
+	mockIterator   *mocks.MockBranchIterator
+	mockBranch     *mocks.MockBranch
+	branchList     List
+}
+
+func TestBranchListTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchListTestSuite))
+}
+
+func (suite *BranchListTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+
+	test_utils.CheckoutTestBranchWithType(suite.repo, "test_remote", git2go.BranchRemote)
+	test_utils.CheckoutTestBranch(suite.repo, "master")
+}
+
+func (suite *BranchListTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockIterator = mocks.NewMockBranchIterator(suite.mockController)
+	suite.mockBranch = mocks.NewMockBranch(suite.mockController)
+	suite.branchList = NewBranchList(suite.mockRepo)
+}
+
+func (suite *BranchListTestSuite) TestListBranches_WhenRepoHasBranches_ShouldReturnBranchList() {
+	suite.branchList = NewBranchList(suite.repo)
+
+	branchList, err := suite.branchList.ListBranches()
+
+	log.Println(branchList)
+
+	suite.Nil(err)
+	suite.Equal(2, len(branchList.BranchList))
+	suite.Equal(3, len(branchList.AllBranchList))
+	suite.Equal("master", branchList.CurrentBranch)
+}
+
+func (suite *BranchListTestSuite) TestListBranches_WhenRepoHeadIsInvalid_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERROR"))
+
+	_, err := suite.branchList.ListBranches()
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchListTestSuite) TestListBranches_WhenNewBranchIteratorFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Name().Return("refs/head/master")
+	suite.mockRepo.EXPECT().NewBranchIterator(git2go.BranchAll).Return(nil, errors.New("ITERATOR_ERR"))
+
+	_, err := suite.branchList.ListBranches()
+
+	suite.NotNil(err)
+}
+
+func (suite *BranchListTestSuite) TestListBranches_WhenBranchIteratorReturnsError_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Name().Return("refs/head/master")
+	suite.mockRepo.EXPECT().NewBranchIterator(git2go.BranchAll).Return(suite.mockIterator, nil)
+	suite.mockIterator.EXPECT().ForEach(gomock.Any()).Return(errors.New("iterator error"))
+
+	_, err := suite.branchList.ListBranches()
+
+	suite.NotNil(err)
+}
diff --git a/git/branch/mocks/mock_branch_validation.go b/git/branch/mocks/mock_branch_validation.go
new file mode 100644
index 0000000..ad3c118
--- /dev/null
+++ b/git/branch/mocks/mock_branch_validation.go
@@ -0,0 +1,52 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/branch/branch_validation.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockValidation is a mock of Validation interface.
+type MockValidation struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidationMockRecorder
+}
+
+// MockValidationMockRecorder is the mock recorder for MockValidation.
+type MockValidationMockRecorder struct {
+	mock *MockValidation
+}
+
+// NewMockValidation creates a new mock instance.
+func NewMockValidation(ctrl *gomock.Controller) *MockValidation {
+	mock := &MockValidation{ctrl: ctrl}
+	mock.recorder = &MockValidationMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidation) EXPECT() *MockValidationMockRecorder {
+	return m.recorder
+}
+
+// ValidateBranchFields mocks base method.
+func (m *MockValidation) ValidateBranchFields(branchNames ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{}
+	for _, a := range branchNames {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateBranchFields", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ValidateBranchFields indicates an expected call of ValidateBranchFields.
+func (mr *MockValidationMockRecorder) ValidateBranchFields(branchNames ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateBranchFields", reflect.TypeOf((*MockValidation)(nil).ValidateBranchFields), branchNames...)
+}
diff --git a/git/branch/mocks/mock_git_branch_add.go b/git/branch/mocks/mock_git_branch_add.go
new file mode 100644
index 0000000..174d835
--- /dev/null
+++ b/git/branch/mocks/mock_git_branch_add.go
@@ -0,0 +1,49 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/branch/git_branch_add.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockAdd is a mock of Add interface.
+type MockAdd struct {
+	ctrl     *gomock.Controller
+	recorder *MockAddMockRecorder
+}
+
+// MockAddMockRecorder is the mock recorder for MockAdd.
+type MockAddMockRecorder struct {
+	mock *MockAdd
+}
+
+// NewMockAdd creates a new mock instance.
+func NewMockAdd(ctrl *gomock.Controller) *MockAdd {
+	mock := &MockAdd{ctrl: ctrl}
+	mock.recorder = &MockAddMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockAdd) EXPECT() *MockAddMockRecorder {
+	return m.recorder
+}
+
+// AddBranch mocks base method.
+func (m *MockAdd) AddBranch(branchName string, remoteSwitch bool, targetCommit *git.Commit) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "AddBranch", branchName, remoteSwitch, targetCommit)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// AddBranch indicates an expected call of AddBranch.
+func (mr *MockAddMockRecorder) AddBranch(branchName, remoteSwitch, targetCommit interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBranch", reflect.TypeOf((*MockAdd)(nil).AddBranch), branchName, remoteSwitch, targetCommit)
+}
diff --git a/git/branch/test_utils/add_branch_util.go b/git/branch/test_utils/add_branch_util.go
new file mode 100644
index 0000000..755b249
--- /dev/null
+++ b/git/branch/test_utils/add_branch_util.go
@@ -0,0 +1,12 @@
+package test_utils
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func AddTestBranch(repo middleware.Repository, branchName string) {
+	head, _ := repo.Head()
+	targetCommit, _ := repo.LookupCommit(head.Target())
+	fmt.Println(repo.CreateBranch(branchName, targetCommit, false))
+}
diff --git a/git/branch/test_utils/checkout_branch_util.go b/git/branch/test_utils/checkout_branch_util.go
new file mode 100644
index 0000000..be04ef7
--- /dev/null
+++ b/git/branch/test_utils/checkout_branch_util.go
@@ -0,0 +1,38 @@
+package test_utils
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func CheckoutTestBranch(repo middleware.Repository, branchName string) {
+	branch, _ := repo.LookupBranch(branchName, git2go.BranchLocal)
+	targetCommit, _ := repo.LookupCommitV2(branch.Target())
+	tree, _ := targetCommit.Tree()
+	_ = repo.CheckoutTree(tree, &git2go.CheckoutOptions{
+		Strategy:       git2go.CheckoutSafe,
+		DisableFilters: false,
+	})
+	fmt.Println(repo.SetHead("refs/heads/" + branchName))
+}
+
+func CheckoutTestBranchWithType(repo middleware.Repository, branchName string, branchType git2go.BranchType) {
+	defer func() {
+		if r := recover(); r != nil {
+			fmt.Println(r)
+		}
+	}()
+
+	branch, err := repo.LookupBranch(branchName, branchType)
+	if err != nil {
+		AddTestBranch(repo, branchName)
+	}
+	targetCommit, _ := repo.LookupCommitV2(branch.Target())
+	tree, _ := targetCommit.Tree()
+	_ = repo.CheckoutTree(tree, &git2go.CheckoutOptions{
+		Strategy:       git2go.CheckoutSafe,
+		DisableFilters: false,
+	})
+	fmt.Println(repo.SetHead("refs/heads/" + branchName))
+}
diff --git a/git/branch/test_utils/delete_branch_util.go b/git/branch/test_utils/delete_branch_util.go
new file mode 100644
index 0000000..0e5ee01
--- /dev/null
+++ b/git/branch/test_utils/delete_branch_util.go
@@ -0,0 +1,12 @@
+package test_utils
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func DeleteTestBranch(repo middleware.Repository, branchName string) {
+	branch, _ := repo.LookupBranch(branchName, git2go.BranchLocal)
+	fmt.Println(branch.Delete())
+}
diff --git a/git/branch/test_utils/stage_and_commit_util.go b/git/branch/test_utils/stage_and_commit_util.go
new file mode 100644
index 0000000..1dfbb1c
--- /dev/null
+++ b/git/branch/test_utils/stage_and_commit_util.go
@@ -0,0 +1,28 @@
+package test_utils
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"io/ioutil"
+)
+
+func StageAndCommitTestFile(repo middleware.Repository, branchName string, testFile string) {
+	AddTestBranch(repo, branchName)
+	CheckoutTestBranch(repo, branchName)
+
+	for i := 1; i <= 2; i++ {
+		err := ioutil.WriteFile(testFile, []byte{byte(i)}, 0644)
+		if err != nil {
+			fmt.Println(err.Error())
+			return
+		}
+
+		git.StageItemStruct{
+			Repo:     repo.GetGitRepository(),
+			FileItem: testFile,
+		}.StageItem()
+		fmt.Println(commit.NewCommitChanges(repo, []string{fmt.Sprintf("Branch compare test commit - %v", i)}).Add())
+	}
+}
diff --git a/git/commit/commit.go b/git/commit/commit.go
new file mode 100644
index 0000000..5382e4b
--- /dev/null
+++ b/git/commit/commit.go
@@ -0,0 +1,67 @@
+package commit
+
+import (
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+var logger global.Logger
+
+type Commit interface {
+	GitCommitChange() (string, error)
+	GitTotalCommits() int
+	GitCommitLogs() ([]*model.GitCommits, error)
+	GitCommitFileHistory(string) ([]*model.GitCommitFileResult, error)
+	GitSearchCommitLogs(string, string) ([]*model.GitCommits, error)
+}
+
+type Operation struct {
+	Changes     Changes
+	Total       Total
+	ListAllLogs ListAllLogs
+	FileHistory FileHistory
+	Lookup      Lookup
+	SearchLogs  SearchLogs
+}
+
+func (c Operation) GitCommitChange() (string, error) {
+	err := c.Changes.Add()
+
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return "", ChangeError
+	}
+
+	return global.CommitChangeSuccess, nil
+}
+
+func (c Operation) GitTotalCommits() int {
+	return c.Total.Get()
+}
+
+func (c Operation) GitCommitLogs() ([]*model.GitCommits, error) {
+	commits, logsErr := c.ListAllLogs.Get()
+	if logsErr != nil {
+		logger.Log(logsErr.Error(), global.StatusError)
+		return nil, LogsError
+	}
+
+	return NewMapper(c.FileHistory).Map(commits), nil
+}
+
+func (c Operation) GitCommitFileHistory(commitHash string) ([]*model.GitCommitFileResult, error) {
+	if commitHash == "" {
+		return nil, EmptyCommitHashError
+	}
+
+	commit, err := c.Lookup.WithReferenceId(commitHash)
+	if err != nil {
+		return nil, err
+	}
+
+	return c.FileHistory.Get(commit)
+}
+
+func (c Operation) GitSearchCommitLogs(searchType string, searchKey string) ([]*model.GitCommits, error) {
+	return c.SearchLogs.GetMatchingLogs(searchType, searchKey)
+}
diff --git a/git/commit/errors.go b/git/commit/errors.go
new file mode 100644
index 0000000..8622db8
--- /dev/null
+++ b/git/commit/errors.go
@@ -0,0 +1,23 @@
+package commit
+
+type Error struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	ChangeError                = Error{ErrorCode: "COMMIT_FAILED", ErrorString: "Failed to commit the new changes"}
+	LogsError                  = Error{ErrorCode: "LIST_COMMIT_LOGS_FAILED", ErrorString: "Failed to list the commit logs for the repo"}
+	FileHistoryError           = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_FAILED", ErrorString: "Failed to get the list of file changes for the commit"}
+	FileHistoryNoParentError   = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_NO_PARENT", ErrorString: "The HEAD commit is the only commit in the repo and has no previous histories"}
+	FileHistoryTreeError       = Error{ErrorCode: "LISTING_COMMIT_FILE_HISTORY_INVALID_TREE", ErrorString: "The commit tree is invalid"}
+	InvalidSearchCategoryError = Error{ErrorCode: "COMMIT_SEARCH_INVALID_SEARCH_TYPE", ErrorString: "The selected search category is invalid"}
+	EmptyCommitHashError       = Error{ErrorCode: "COMMIT_HASH_REQUIRED", ErrorString: "Commit hash cannot be empty"}
+	OidConversionError         = Error{ErrorCode: "INVALID_HASH_FOR_OID_CONVERSION", ErrorString: "Commit hash cannot be converted into an OID for commit lookup"}
+	CommitLookupError          = Error{ErrorCode: "COMMIT_LOOKUP_FAILED", ErrorString: "Unable to find commit with the OID"}
+)
+
+func (e Error) Error() string {
+	return e.ErrorString
+}
diff --git a/git/commit/git_commit_changes.go b/git/commit/git_commit_changes.go
new file mode 100644
index 0000000..0bb2f13
--- /dev/null
+++ b/git/commit/git_commit_changes.go
@@ -0,0 +1,158 @@
+package commit
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"strings"
+)
+
+type Changes interface {
+	Add() error
+}
+
+type changes struct {
+	repo          middleware.Repository
+	commitMessage []string
+}
+
+// Add commits the staged changes to the repo
+// Rewrites the repo index tree with the staged files to commit the changes
+func (c changes) Add() error {
+	var (
+		headCommit       *git2go.Commit
+		formattedMessage string
+		repo             = c.repo
+	)
+
+	signature, err := c.validateSignature(repo)
+	if err != nil {
+		return err
+	}
+
+	formattedMessage = c.formatCommitMessage()
+
+	headCommit, headCommitErr := c.currentHeadCommit()
+	if headCommitErr != nil {
+		logger.Log(headCommitErr.Error(), global.StatusError)
+		return headCommitErr
+	}
+
+	newTree, treeErr := c.treeForNewCommit(repo)
+	if treeErr != nil {
+		logger.Log(treeErr.Error(), global.StatusError)
+		return treeErr
+	}
+
+	newCommitId, newCommitIdErr := c.createNewCommit(headCommit, repo, signature, formattedMessage, newTree)
+	if newCommitIdErr != nil {
+		logger.Log(newCommitIdErr.Error(), global.StatusError)
+		return newCommitIdErr
+	}
+
+	setHeadErr := c.setHeadToNewCommit(repo, newCommitId, formattedMessage)
+	if setHeadErr != nil {
+		logger.Log(setHeadErr.Error(), global.StatusError)
+		return setHeadErr
+	}
+
+	logger.Log(fmt.Sprintf("New commit %s created", newCommitId.String()), global.StatusInfo)
+	return nil
+}
+
+func (c changes) validateSignature(repo middleware.Repository) (*git2go.Signature, error) {
+	signature, signatureErr := repo.DefaultSignature()
+	if signatureErr != nil {
+		logger.Log(fmt.Sprintf("Error occurred while fetching repo signature -> %s", signatureErr.Error()), global.StatusError)
+		logger.Log("Setup you user name and email using `git config user.name and git config user.email`", global.StatusWarning)
+		return nil, signatureErr
+	}
+
+	return signature, nil
+}
+
+func (c changes) setHeadToNewCommit(repo middleware.Repository, newCommitId *git2go.Oid, formattedMessage string) error {
+	if _, newCommitErr := repo.LookupCommit(newCommitId); newCommitErr != nil {
+		logger.Log(newCommitErr.Error(), global.StatusError)
+		return newCommitErr
+	}
+
+	head, headErr := repo.Head()
+	if headErr != nil {
+		logger.Log(headErr.Error(), global.StatusError)
+		return headErr
+	}
+
+	_, newRefErr := head.SetTarget(newCommitId, formattedMessage)
+	if newRefErr != nil {
+		logger.Log(newRefErr.Error(), global.StatusError)
+		return newRefErr
+	}
+
+	return nil
+}
+
+func (c changes) createNewCommit(headCommit *git2go.Commit, repo middleware.Repository, signature *git2go.Signature, formattedMessage string, newTree *git2go.Tree) (*git2go.Oid, error) {
+	var (
+		newCommitId    *git2go.Oid
+		newCommitIdErr error
+	)
+
+	if headCommit == nil {
+		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree)
+	} else {
+		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree, headCommit)
+	}
+
+	return newCommitId, newCommitIdErr
+}
+
+func (c changes) treeForNewCommit(repo middleware.Repository) (*git2go.Tree, error) {
+	treeId, indexErr := c.updateRepoIndex()
+	if indexErr != nil {
+		logger.Log(indexErr.Error(), global.StatusError)
+		return nil, indexErr
+	}
+
+	newTree, newTreeErr := repo.LookupTree(treeId)
+	if newTreeErr != nil {
+		logger.Log(newTreeErr.Error(), global.StatusError)
+		return nil, newTreeErr
+	}
+	return newTree, nil
+}
+
+func (c changes) updateRepoIndex() (*git2go.Oid, error) {
+	repoIndex, indexErr := c.repo.Index()
+	if indexErr != nil {
+		return nil, indexErr
+	}
+
+	return repoIndex.WriteTree()
+}
+
+func (c changes) currentHeadCommit() (*git2go.Commit, error) {
+	head, headErr := c.repo.Head()
+	if headErr != nil {
+		logger.Log("Repo has no HEAD. Proceeding with a NIL HEAD", global.StatusWarning)
+		return nil, nil
+	}
+
+	return c.repo.LookupCommit(head.Target())
+}
+
+func (c changes) formatCommitMessage() string {
+	if len(c.commitMessage) > 0 {
+		return strings.Join(c.commitMessage, "\n")
+	}
+
+	return strings.Join(c.commitMessage, "")
+}
+
+func NewCommitChanges(repo middleware.Repository, message []string) Changes {
+	return changes{
+		repo:          repo,
+		commitMessage: message,
+	}
+}
diff --git a/git/commit/git_commit_changes_test.go b/git/commit/git_commit_changes_test.go
new file mode 100644
index 0000000..9b1c15f
--- /dev/null
+++ b/git/commit/git_commit_changes_test.go
@@ -0,0 +1,216 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+	"time"
+)
+
+type CommitChangesTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	repo           middleware.Repository
+	noHeadRepo     middleware.Repository
+	commitChanges  Changes
+	commitMessage  []string
+	mockRepo       *mocks.MockRepository
+	mockReference  *mocks.MockReference
+	mockIndex      *mocks.MockIndex
+}
+
+func TestCommitChangesTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitChangesTestSuite))
+}
+
+func (suite *CommitChangesTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head_for_commit"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.repo = middleware.NewRepository(r)
+	suite.noHeadRepo = middleware.NewRepository(noHeadRepo)
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.mockIndex = mocks.NewMockIndex(suite.mockController)
+
+	suite.commitMessage = []string{"Test commit message " + time.Now().String()}
+	suite.commitChanges = NewCommitChanges(suite.mockRepo, suite.commitMessage)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenChangesAreCommitted_ShouldReturnNil() {
+	suite.commitChanges = NewCommitChanges(suite.repo, suite.commitMessage)
+
+	err := suite.commitChanges.Add()
+
+	suite.Nil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenCommitMessageIsMultiLine_ShouldCommitToRepo() {
+	suite.commitChanges = NewCommitChanges(suite.repo, []string{"Multi line commit", "Test 1"})
+
+	err := suite.commitChanges.Add()
+
+	suite.Nil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHasNoSignature_ShouldReturnError() {
+	suite.mockRepo.EXPECT().DefaultSignature().Return(nil, errors.New("SIGNATURE_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHasNoHead_ShouldCommitToHead() {
+	suite.commitMessage = []string{""}
+	suite.commitChanges = NewCommitChanges(suite.repo, suite.commitMessage)
+
+	err := suite.commitChanges.Add()
+
+	suite.Nil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoHeadIsInvalid_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoIndexIsInvalid_ShouldReturnError() {
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(nil, errors.New("INDEX_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenRepoTreeLookupFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(nil, errors.New("TREE_LOOKUP_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenCommitCreation_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		strings.Join(suite.commitMessage, ""),
+		&git2go.Tree{},
+	).Return(nil, errors.New("CREATE_COMMIT_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenNewCommitLookupFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+	commitMessage := strings.Join(suite.commitMessage, "")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		commitMessage,
+		&git2go.Tree{},
+	).Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenNewHeadIsInvalid_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+	commitMessage := strings.Join(suite.commitMessage, "")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		commitMessage,
+		&git2go.Tree{},
+	).Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("HEAD_ERR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
+
+func (suite *CommitChangesTestSuite) TestAdd_WhenSetNewHeadFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("test")
+	commitMessage := strings.Join(suite.commitMessage, "")
+
+	suite.mockRepo.EXPECT().DefaultSignature().Return(&git2go.Signature{}, nil)
+	suite.mockRepo.EXPECT().Head().Return(nil, errors.New("NO_HEAD"))
+	suite.mockRepo.EXPECT().Index().Return(suite.mockIndex, nil)
+	suite.mockIndex.EXPECT().WriteTree().Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupTree(oid).Return(&git2go.Tree{}, nil)
+	suite.mockRepo.EXPECT().CreateCommit(
+		"HEAD",
+		&git2go.Signature{},
+		&git2go.Signature{},
+		commitMessage,
+		&git2go.Tree{},
+	).Return(oid, nil)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, nil)
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().SetTarget(oid, commitMessage).Return(nil, errors.New("SET_TARGET_ERROR"))
+
+	err := suite.commitChanges.Add()
+
+	suite.NotNil(err)
+}
diff --git a/git/commit/git_commit_file_history.go b/git/commit/git_commit_file_history.go
new file mode 100644
index 0000000..5b6ba25
--- /dev/null
+++ b/git/commit/git_commit_file_history.go
@@ -0,0 +1,90 @@
+package commit
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+	"reflect"
+)
+
+type FileHistory interface {
+	Get(commit middleware.Commit) ([]*model.GitCommitFileResult, error)
+}
+
+type fileHistory struct {
+	repo middleware.Repository
+}
+
+func (f fileHistory) Get(commit middleware.Commit) ([]*model.GitCommitFileResult, error) {
+	commitHash := commit.Id().String()
+	logger.Log(fmt.Sprintf("Fetching file details for commit %v", commitHash), global.StatusInfo)
+
+	prevTree, commitTree, treeErr := f.treesOf(commit)
+	if treeErr != nil {
+		return fileHistoryError(treeErr)
+	}
+
+	return f.diffBetweenTrees(prevTree, commitTree)
+}
+
+func (f fileHistory) treesOf(commit middleware.Commit) (*git2go.Tree, *git2go.Tree, error) {
+	var treeErr error
+	logger.Log("Getting current and previous trees", global.StatusInfo)
+
+	parents := commit.ParentCount()
+	if parents == 0 {
+		logger.Log("Commit has no parent", global.StatusError)
+		return nil, nil, FileHistoryNoParentError
+	}
+
+	previousCommit := commit.Parent(0)
+
+	previousTree, treeErr := previousCommit.Tree()
+	currentTree, treeErr := commit.Tree()
+	if treeErr != nil {
+		logger.Log(treeErr.Error(), global.StatusError)
+		return nil, nil, FileHistoryTreeError
+	}
+
+	return previousTree, currentTree, nil
+}
+
+func (f fileHistory) diffBetweenTrees(previousTree *git2go.Tree, currentTree *git2go.Tree) ([]*model.GitCommitFileResult, error) {
+	var history []*model.GitCommitFileResult
+
+	logger.Log("Checking diff between trees", global.StatusInfo)
+	diff, diffErr := f.repo.DiffTreeToTree(previousTree, currentTree, nil)
+	if diffErr != nil {
+		return fileHistoryError(diffErr)
+	}
+
+	numDelta, numDeltaErr := diff.NumDeltas()
+	if numDeltaErr != nil {
+		return fileHistoryError(numDeltaErr)
+	}
+
+	for d := 0; d < numDelta; d++ {
+		delta, _ := diff.Delta(d)
+		status := delta.Status.String()
+		history = append(history, &model.GitCommitFileResult{
+			Type:     status[0:1],
+			FileName: delta.NewFile.Path,
+		})
+	}
+
+	return history, nil
+}
+
+func fileHistoryError(err error) ([]*model.GitCommitFileResult, error) {
+	logger.Log(err.Error(), global.StatusError)
+	if reflect.TypeOf(err) != reflect.TypeOf(Error{}) {
+		return nil, FileHistoryError
+	}
+	return nil, err
+}
+
+func NewFileHistory(repo middleware.Repository) FileHistory {
+	return fileHistory{repo: repo}
+}
diff --git a/git/commit/git_commit_file_history_test.go b/git/commit/git_commit_file_history_test.go
new file mode 100644
index 0000000..98298d8
--- /dev/null
+++ b/git/commit/git_commit_file_history_test.go
@@ -0,0 +1,120 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type FileHistoryTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	repo           middleware.Repository
+	mockRepo       *mocks.MockRepository
+	mockCommit     *mocks.MockCommit
+	fileHistory    FileHistory
+}
+
+func TestFileHistoryTestSuite(t *testing.T) {
+	suite.Run(t, new(FileHistoryTestSuite))
+}
+
+func (suite *FileHistoryTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.repo = middleware.NewRepository(r)
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockCommit = mocks.NewMockCommit(suite.mockController)
+	suite.fileHistory = NewFileHistory(suite.mockRepo)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenRepoHasMoreThanOneCommit_ShouldReturnDiffForChosenCommit() {
+	suite.fileHistory = NewFileHistory(suite.repo)
+	commitLogs := suite.commitLogs()
+
+	commit, _ := suite.repo.LookupCommit(commitLogs[len(commitLogs)-2].Id())
+
+	gotHistory, err := suite.fileHistory.Get(middleware.NewCommit(commit))
+
+	suite.Nil(err)
+	suite.NotZero(len(gotHistory))
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenCommitIsTheFirstCommitWithNoParents_ShouldReturnNoParentError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(0))
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(FileHistoryNoParentError, err)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenCommitTreeIsInvalid_ShouldReturnTreeError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(1))
+	suite.mockCommit.EXPECT().Parent(uint(0)).Return(suite.mockCommit)
+	suite.mockCommit.EXPECT().Tree().Return(nil, errors.New("TREE_ERROR")).Times(2)
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(FileHistoryTreeError, err)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenDiffTreeFails_ShouldReturnError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+	treePtr := &git2go.Tree{Object: git2go.Object{}}
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(1))
+	suite.mockCommit.EXPECT().Parent(uint(0)).Return(suite.mockCommit)
+	suite.mockCommit.EXPECT().Tree().Return(treePtr, nil).Times(2)
+
+	suite.mockRepo.EXPECT().DiffTreeToTree(treePtr, treePtr, nil).Return(nil, errors.New("DIFF_ERROR"))
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(FileHistoryError, err)
+}
+
+func (suite *FileHistoryTestSuite) TestGet_WhenDiffNumDeltaIsZero_ShouldReturnError() {
+	oid, _ := git2go.NewOid("5e0c30593a8819a05135f908e1729278d3ee086e")
+	treePtr := &git2go.Tree{Object: git2go.Object{}}
+
+	suite.mockCommit.EXPECT().Id().Return(oid)
+	suite.mockCommit.EXPECT().ParentCount().Return(uint(1))
+	suite.mockCommit.EXPECT().Parent(uint(0)).Return(suite.mockCommit)
+	suite.mockCommit.EXPECT().Tree().Return(treePtr, nil).Times(2)
+
+	suite.mockRepo.EXPECT().DiffTreeToTree(treePtr, treePtr, nil).Return(&git2go.Diff{}, nil)
+
+	_, err := suite.fileHistory.Get(suite.mockCommit)
+
+	suite.NotNil(err)
+	suite.Equal(FileHistoryError, err)
+}
+
+func (suite *FileHistoryTestSuite) commitLogs() []git2go.Commit {
+	commits, err := NewListAllLogs(suite.repo, nil, nil).Get()
+	if err != nil {
+		return nil
+	}
+
+	return commits
+}
diff --git a/git/commit/git_commit_log_mapper.go b/git/commit/git_commit_log_mapper.go
new file mode 100644
index 0000000..954508e
--- /dev/null
+++ b/git/commit/git_commit_log_mapper.go
@@ -0,0 +1,82 @@
+package commit
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+	"strings"
+)
+
+type Mapper interface {
+	Map([]git2go.Commit) []*model.GitCommits
+}
+
+type mapper struct {
+	fileHistory FileHistory
+}
+
+type mapperCommitType struct {
+	hash       *string
+	author     *string
+	commitTime *string
+	message    *string
+	filesCount *int
+}
+
+func (m mapper) Map(commits []git2go.Commit) []*model.GitCommits {
+	var mappedCommits []*model.GitCommits
+
+	if len(commits) == 0 {
+		logger.Log("No commits received for mapping", global.StatusWarning)
+		return nil
+	}
+
+	for _, commit := range commits {
+		commitFields := m.commitFields(commit)
+
+		mappedCommits = append(mappedCommits, &model.GitCommits{
+			Hash:             commitFields.hash,
+			Author:           commitFields.author,
+			CommitTime:       commitFields.commitTime,
+			CommitMessage:    commitFields.message,
+			CommitFilesCount: commitFields.filesCount,
+		})
+	}
+
+	return mappedCommits
+}
+
+func (m mapper) commitFields(commit git2go.Commit) mapperCommitType {
+	commitHash := commit.Id().String()
+	commitAuthor := strings.Split(commit.Author().Name, " ")[0]
+	commitMessage := strings.Split(commit.Message(), "\n")[0]
+	commitDate := commit.Committer().When.String()
+	commitFileHistory := m.commitFileHistory(commit)
+
+	commitFields := mapperCommitType{
+		hash:       &commitHash,
+		author:     &commitAuthor,
+		commitTime: &commitDate,
+		message:    &commitMessage,
+		filesCount: &commitFileHistory,
+	}
+	return commitFields
+}
+
+func (m mapper) commitFileHistory(commit git2go.Commit) int {
+	c := middleware.NewCommit(&commit)
+	fileHistory, err := m.fileHistory.Get(c)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return 0
+	}
+
+	return len(fileHistory)
+}
+
+func NewMapper(commitFile FileHistory) Mapper {
+	return mapper{
+		fileHistory: commitFile,
+	}
+}
diff --git a/git/commit/git_commit_log_mapper_test.go b/git/commit/git_commit_log_mapper_test.go
new file mode 100644
index 0000000..eeb2c9c
--- /dev/null
+++ b/git/commit/git_commit_log_mapper_test.go
@@ -0,0 +1,87 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"strings"
+	"testing"
+)
+
+type CommitLogMapperTestSuite struct {
+	suite.Suite
+	mockController  *gomock.Controller
+	repo            middleware.Repository
+	mockRepo        *mocks.MockRepository
+	fileHistory     FileHistory
+	mockFileHistory *commitMocks.MockFileHistory
+	commits         []git2go.Commit
+	mapper          Mapper
+}
+
+func TestCommitLogMapperTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitLogMapperTestSuite))
+}
+
+func (suite *CommitLogMapperTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = middleware.NewRepository(r)
+
+	limit := uint(3)
+	commits, _ := NewListAllLogs(suite.repo, &limit, nil).Get()
+	suite.commits = commits
+
+	suite.fileHistory = NewFileHistory(suite.repo)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockFileHistory = commitMocks.NewMockFileHistory(suite.mockController)
+
+	suite.mapper = NewMapper(suite.mockFileHistory)
+}
+
+func (suite *CommitLogMapperTestSuite) TestMap_ShouldMapCommitLogFieldsToModel() {
+	suite.mapper = NewMapper(suite.fileHistory)
+
+	got := suite.mapper.Map(suite.commits)
+
+	wantFileCount, _ := suite.fileHistory.Get(middleware.NewCommit(&suite.commits[0]))
+
+	suite.Len(got, 3)
+	suite.Equal(suite.commits[0].Id().String(), *got[0].Hash)
+	suite.Equal(suite.commits[0].Author().Name, *got[0].Author)
+	suite.Equal(suite.commits[0].Author().When.String(), *got[0].CommitTime)
+	suite.Equal(strings.Split(suite.commits[0].Message(), "\n")[0], *got[0].CommitMessage)
+	suite.Equal(len(wantFileCount), *got[0].CommitFilesCount)
+}
+
+func (suite *CommitLogMapperTestSuite) TestMap_WhenCommitListIsEmpty_ShouldReturnEmptyModelSlice() {
+	suite.mapper = NewMapper(suite.fileHistory)
+
+	got := suite.mapper.Map([]git2go.Commit{})
+
+	suite.Len(got, 0)
+}
+
+func (suite *CommitLogMapperTestSuite) TestMap_WhenCommitFileHistoryReturnsError_ShouldConsiderFileHistoryAsZero() {
+	suite.mapper = NewMapper(suite.mockFileHistory)
+
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&suite.commits[0])).Return(nil, errors.New("FILE_HISTORY_ERROR")).Times(3)
+
+	got := suite.mapper.Map(suite.commits)
+
+	suite.Len(got, 3)
+	suite.Equal(suite.commits[0].Id().String(), *got[0].Hash)
+	suite.Equal(suite.commits[0].Author().Name, *got[0].Author)
+	suite.Equal(suite.commits[0].Author().When.String(), *got[0].CommitTime)
+	suite.Equal(strings.Split(suite.commits[0].Message(), "\n")[0], *got[0].CommitMessage)
+	suite.Equal(0, *got[0].CommitFilesCount)
+}
diff --git a/git/commit/git_commit_log_search.go b/git/commit/git_commit_log_search.go
new file mode 100644
index 0000000..751f9bc
--- /dev/null
+++ b/git/commit/git_commit_log_search.go
@@ -0,0 +1,48 @@
+package commit
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/commit/search"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type SearchLogs interface {
+	GetMatchingLogs(searchType string, searchKey string) ([]*model.GitCommits, error)
+}
+
+type searchLogs struct {
+	repo           middleware.Repository
+	listCommitLogs ListAllLogs
+	mapper         Mapper
+}
+
+// GetMatchingLogs searches for the required commits matching the searchKey with the respective searchType
+//
+// The UI uses 'message' as the default search type to look up based on commit messages
+func (s searchLogs) GetMatchingLogs(searchType string, searchKey string) ([]*model.GitCommits, error) {
+	logger.Log(fmt.Sprintf("Searching commit logs filtered with - %s for -> %s", searchType, searchKey), global.StatusInfo)
+
+	commits, listErr := s.listCommitLogs.Get()
+	if listErr != nil {
+		logger.Log("Unable to fetch commit logs : "+listErr.Error(), global.StatusError)
+		return nil, listErr
+	}
+
+	searchFactory := search.GetSearchAction(searchType, commits)
+	if searchFactory == nil {
+		logger.Log("Invalid search category", global.StatusError)
+		return nil, InvalidSearchCategoryError
+	}
+
+	return s.mapper.Map(searchFactory.Search(searchKey)), nil
+}
+
+func NewSearchLogs(repo middleware.Repository, listCommitLogs ListAllLogs, mapper Mapper) SearchLogs {
+	return searchLogs{
+		repo:           repo,
+		listCommitLogs: listCommitLogs,
+		mapper:         mapper,
+	}
+}
diff --git a/git/commit/git_commit_log_search_test.go b/git/commit/git_commit_log_search_test.go
new file mode 100644
index 0000000..721bd45
--- /dev/null
+++ b/git/commit/git_commit_log_search_test.go
@@ -0,0 +1,195 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"strings"
+	"testing"
+)
+
+type SearchLogsTestSuite struct {
+	suite.Suite
+	mockController  *gomock.Controller
+	mockRepo        *mocks.MockRepository
+	mockListLogs    *commitMocks.MockListAllLogs
+	mockFileHistory *commitMocks.MockFileHistory
+	listAllLogs     ListAllLogs
+	mapper          Mapper
+	searchLogs      SearchLogs
+}
+
+func TestSearchLogsTestSuite(t *testing.T) {
+	suite.Run(t, new(SearchLogsTestSuite))
+}
+
+func (suite *SearchLogsTestSuite) SetupSuite() {
+	r, err := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.listAllLogs = NewListAllLogs(middleware.NewRepository(r), nil, nil)
+}
+
+func (suite *SearchLogsTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockListLogs = commitMocks.NewMockListAllLogs(suite.mockController)
+	suite.mockFileHistory = commitMocks.NewMockFileHistory(suite.mockController)
+
+	suite.mapper = NewMapper(suite.mockFileHistory)
+	suite.searchLogs = NewSearchLogs(suite.mockRepo, suite.mockListLogs, suite.mapper)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsHash_ShouldReturnMatchingCommits() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Id().String()[0:8]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
+
+	got, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].Hash, *got[0].Hash)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsMessage_ShouldReturnMatchingCommits() {
+	commits := suite.commitLogs()
+	wantCommit := commits[len(commits)-1]
+	searchKey := strings.Split(wantCommit.Message(), " ")[0]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
+
+	got, err := suite.searchLogs.GetMatchingLogs("message", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].CommitMessage, *got[0].CommitMessage)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsAuthor_ShouldReturnMatchingCommits() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Author().Name[0:3]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
+
+	got, err := suite.searchLogs.GetMatchingLogs("author", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].Author, *got[0].Author)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenSearchTypeIsInvalid_ShouldReturnError() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Author().Name[0:3]
+
+	suite.mockListLogs.EXPECT().Get().Return(commits, nil)
+
+	_, err := suite.searchLogs.GetMatchingLogs("invalid", searchKey)
+
+	suite.NotNil(err)
+	suite.Equal(InvalidSearchCategoryError, err)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenListLogsReturnsError_ShouldReturnError() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Author().Name[0:3]
+
+	suite.mockListLogs.EXPECT().Get().Return(nil, errors.New("LIST_LOGS_ERROR"))
+
+	_, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
+
+	suite.NotNil(err)
+}
+
+func (suite *SearchLogsTestSuite) TestGetMatchingLogs_WhenCommitLogsExceedsSearchLimit_ShouldReturnMatchingLogsWithinLimit() {
+	commits := suite.commitLogs()
+	wantCommit := commits[0]
+	searchKey := wantCommit.Id().String()[0:8]
+
+	want := bindWithModel([]git.Commit{wantCommit})
+
+	suite.mockListLogs.EXPECT().Get().Return(suite.commitLogsExceedingLimit(wantCommit), nil)
+	suite.mockFileHistory.EXPECT().Get(middleware.NewCommit(&wantCommit)).Return(
+		[]*model.GitCommitFileResult{{}},
+		nil,
+	).MaxTimes(constants.SearchLimit)
+
+	got, err := suite.searchLogs.GetMatchingLogs("hash", searchKey)
+
+	suite.Nil(err)
+	suite.Equal(*want[0].Hash, *got[0].Hash)
+	suite.Len(got, constants.SearchLimit)
+}
+
+func bindWithModel(commits []git.Commit) []*model.GitCommits {
+	var mappedCommits []*model.GitCommits
+
+	for _, commit := range commits {
+		wantedHash := commit.Id().String()
+		wantedAuthor := commit.Author().Name
+		wantedTime := commit.Author().When.String()
+		wantedMessage := strings.TrimSpace(commit.Message())
+		wantedFileCount := 1
+
+		mappedCommits = append(mappedCommits, &model.GitCommits{
+			Hash:             &wantedHash,
+			Author:           &wantedAuthor,
+			CommitTime:       &wantedTime,
+			CommitMessage:    &wantedMessage,
+			CommitFilesCount: &wantedFileCount,
+		})
+	}
+
+	return mappedCommits
+}
+
+func (suite *SearchLogsTestSuite) commitLogs() []git.Commit {
+	commits, err := suite.listAllLogs.Get()
+	if err != nil {
+		return nil
+	}
+
+	return commits
+}
+
+func (suite *SearchLogsTestSuite) commitLogsExceedingLimit(commit git.Commit) []git.Commit {
+	var commits []git.Commit
+	limit := constants.SearchLimit * 2
+
+	for i := 0; i < limit; i++ {
+		commits = append(commits, commit)
+	}
+
+	return commits
+}
diff --git a/git/commit/git_commit_lookup.go b/git/commit/git_commit_lookup.go
new file mode 100644
index 0000000..1c31f9c
--- /dev/null
+++ b/git/commit/git_commit_lookup.go
@@ -0,0 +1,35 @@
+package commit
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Lookup interface {
+	WithReferenceId(string) (middleware.Commit, error)
+}
+
+type lookup struct {
+	repo middleware.Repository
+}
+
+func (l lookup) WithReferenceId(commitHash string) (middleware.Commit, error) {
+	oid, oidErr := git2go.NewOid(commitHash)
+	if oidErr != nil {
+		logger.Log(oidErr.Error(), global.StatusError)
+		return nil, OidConversionError
+	}
+
+	commit, err := l.repo.LookupCommit(oid)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return nil, CommitLookupError
+	}
+
+	return middleware.NewCommit(commit), nil
+}
+
+func NewLookup(repo middleware.Repository) Lookup {
+	return lookup{repo: repo}
+}
diff --git a/git/commit/git_commit_lookup_test.go b/git/commit/git_commit_lookup_test.go
new file mode 100644
index 0000000..3fe7c8d
--- /dev/null
+++ b/git/commit/git_commit_lookup_test.go
@@ -0,0 +1,74 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitLookupTestSuite struct {
+	suite.Suite
+	repo           middleware.Repository
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	commitHash     string
+	lookup         Lookup
+}
+
+func TestCommitLookupTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitLookupTestSuite))
+}
+
+func (suite *CommitLookupTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	commits, _ := NewListAllLogs(middleware.NewRepository(r), nil, nil).Get()
+
+	suite.commitHash = commits[0].Id().String()
+}
+
+func (suite *CommitLookupTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.lookup = NewLookup(suite.repo)
+}
+
+func (suite *CommitLookupTestSuite) TestWithReference_WhenCommitHashIsValid_ShouldReturnCommit() {
+	wantCommit, err := suite.lookup.WithReferenceId(suite.commitHash)
+
+	suite.Nil(err)
+	suite.Equal(suite.commitHash, wantCommit.Id().String())
+}
+
+func (suite *CommitLookupTestSuite) TestWithReference_WhenCommitHashIsInValid_ShouldReturnError() {
+	_, err := suite.lookup.WithReferenceId("INVALID_HASH")
+
+	suite.NotNil(err)
+	suite.Equal(OidConversionError, err)
+}
+
+func (suite *CommitLookupTestSuite) TestWithReference_WhenCommitIsNotPresentInTheRepo_ShouldReturnError() {
+	suite.lookup = NewLookup(suite.mockRepo)
+
+	oid, _ := git2go.NewOid("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3")
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERR"))
+
+	_, err := suite.lookup.WithReferenceId("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3")
+
+	suite.NotNil(err)
+	suite.Equal(CommitLookupError, err)
+}
diff --git a/git/commit/git_latest_commit_message.go b/git/commit/git_latest_commit_message.go
new file mode 100644
index 0000000..d130d32
--- /dev/null
+++ b/git/commit/git_latest_commit_message.go
@@ -0,0 +1,53 @@
+package commit
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"strings"
+)
+
+type LatestMessage interface {
+	Get() string
+}
+
+type latestMessage struct {
+	repo middleware.Repository
+}
+
+func (l latestMessage) Get() string {
+	head, err := l.repo.Head()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return ""
+	}
+
+	commit := head.Target()
+
+	lookupCommit, lookupError := l.repo.LookupCommit(commit)
+	if lookupError != nil {
+		logger.Log("Unable to lookup commit : "+lookupError.Error(), global.StatusError)
+		return ""
+	}
+
+	commitMessage := lookupCommit.Message()
+	if commitMessage != "" {
+		return l.truncateMultilineMessage(commitMessage)
+	}
+
+	return commitMessage
+}
+
+func (l latestMessage) truncateMultilineMessage(commitMessage string) string {
+	if strings.Contains(commitMessage, "\n") {
+		logger.Log("Truncating multiline commit message", global.StatusInfo)
+		commitMessage = strings.Split(commitMessage, "\n")[0]
+	}
+
+	logger.Log(fmt.Sprintf("HEAD commit message is : %v", commitMessage), global.StatusInfo)
+	return commitMessage
+}
+
+func NewLatestMessage(repo middleware.Repository) LatestMessage {
+	return latestMessage{repo: repo}
+}
diff --git a/git/commit/git_latest_commit_message_test.go b/git/commit/git_latest_commit_message_test.go
new file mode 100644
index 0000000..aa7a062
--- /dev/null
+++ b/git/commit/git_latest_commit_message_test.go
@@ -0,0 +1,101 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+type LatestMessageTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	latestMessage  LatestMessage
+	repo           middleware.Repository
+	noHeadRepo     *git2go.Repository
+	mockRepo       *mocks.MockRepository
+	mockWalker     *mocks.MockRevWalk
+	mockReference  *mocks.MockReference
+}
+
+func TestLatestMessageTestSuite(t *testing.T) {
+	suite.Run(t, new(LatestMessageTestSuite))
+}
+
+func (suite *LatestMessageTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.repo = middleware.NewRepository(r)
+
+	_ = NewCommitChanges(suite.repo, []string{"New commit"}).Add()
+
+	suite.noHeadRepo = noHeadRepo
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
+	suite.mockReference = mocks.NewMockReference(suite.mockController)
+	suite.latestMessage = NewLatestMessage(suite.mockRepo)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenHeadIsValid_ShouldReturnCommitMessage() {
+	_ = NewCommitChanges(suite.repo, []string{"New commit"}).Add()
+
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.NotEmpty(got)
+	suite.Equal("New commit", got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenCommitMessageIsMultiLine_ShouldReturnFirstLineOfTheMessage() {
+	_ = NewCommitChanges(suite.repo, []string{"New commit", "with two lines"}).Add()
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.NotEmpty(got)
+	suite.Equal("New commit", got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenCommitMessageIsEmpty_ShouldReturnEmptyMessage() {
+	_ = NewCommitChanges(suite.repo, []string{""}).Add()
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.Empty(got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenHeadIsInValid_ShouldReturnEmptyMessage() {
+	suite.repo = middleware.NewRepository(suite.noHeadRepo)
+	suite.latestMessage = NewLatestMessage(suite.repo)
+
+	got := suite.latestMessage.Get()
+
+	suite.Empty(got)
+}
+
+func (suite *LatestMessageTestSuite) TestGet_WhenCommitLookupFails_ShouldReturnEmptyMessage() {
+	oid, _ := git2go.NewOid("test")
+
+	suite.mockRepo.EXPECT().Head().Return(suite.mockReference, nil)
+	suite.mockReference.EXPECT().Target().Return(oid)
+	suite.mockRepo.EXPECT().LookupCommit(oid).Return(nil, errors.New("LOOKUP_ERROR"))
+
+	got := suite.latestMessage.Get()
+
+	suite.Empty(got)
+}
diff --git a/git/commit/git_list_all_commit_logs.go b/git/commit/git_list_all_commit_logs.go
new file mode 100644
index 0000000..b36daa6
--- /dev/null
+++ b/git/commit/git_list_all_commit_logs.go
@@ -0,0 +1,109 @@
+package commit
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type ListAllLogs interface {
+	Get() ([]git2go.Commit, error)
+}
+
+type listAllLogs struct {
+	repo      middleware.Repository
+	limit     *uint
+	reference *git2go.Oid
+}
+
+type commitType struct {
+	commits []git2go.Commit
+}
+
+func (l listAllLogs) Get() ([]git2go.Commit, error) {
+	repo := l.repo
+
+	logItr, itrErr := repo.Walk()
+	if itrErr != nil {
+		logger.Log(fmt.Sprintf("Repo has no logs -> %s", itrErr.Error()), global.StatusError)
+		return nil, itrErr
+	}
+
+	commits, err := l.allCommitLogs(logItr)
+	if err != nil {
+		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
+		return nil, err
+	}
+
+	return commits, nil
+}
+
+func (l listAllLogs) allCommitLogs(logItr middleware.RevWalk) ([]git2go.Commit, error) {
+	var (
+		c commitType
+	)
+
+	pushErr := l.pushCommitReference(logItr)
+	if pushErr != nil {
+		logger.Log(pushErr.Error(), global.StatusError)
+		return nil, pushErr
+	}
+
+	err := l.iterate(logItr, &c)
+
+	return c.commits, err
+}
+
+func (l listAllLogs) iterate(logItr middleware.RevWalk, c *commitType) error {
+	if l.limit == nil {
+		logger.Log("Iterating commit logs without limit", global.StatusInfo)
+		return logItr.Iterate(revIterator(c))
+	}
+
+	logger.Log(fmt.Sprintf("Iterating commit logs with limit %v", *l.limit), global.StatusInfo)
+	return logItr.Iterate(revIteratorWithLimit(c, *l.limit))
+}
+
+func (l listAllLogs) pushCommitReference(logItr middleware.RevWalk) error {
+	if l.reference != nil {
+		logger.Log(fmt.Sprintf("Iterating commits from reference %s", l.reference), global.StatusInfo)
+		return logItr.Push(l.reference)
+	}
+
+	logger.Log(fmt.Sprintf("Iterating commits from HEAD"), global.StatusInfo)
+	return logItr.PushHead()
+}
+
+func revIterator(c *commitType) git2go.RevWalkIterator {
+	return func(commit *git2go.Commit) bool {
+		if commit != nil {
+			c.commits = append(c.commits, *commit)
+			return true
+		}
+
+		return false
+	}
+}
+
+func revIteratorWithLimit(c *commitType, limit uint) git2go.RevWalkIterator {
+	var commitCounter uint
+
+	return func(commit *git2go.Commit) bool {
+		if commit != nil && commitCounter < limit {
+			c.commits = append(c.commits, *commit)
+			commitCounter++
+			return true
+		}
+
+		return false
+	}
+}
+
+func NewListAllLogs(repo middleware.Repository, limit *uint, reference *git2go.Oid) ListAllLogs {
+	return listAllLogs{
+		repo:      repo,
+		limit:     limit,
+		reference: reference,
+	}
+}
diff --git a/git/commit/git_list_all_commit_logs_test.go b/git/commit/git_list_all_commit_logs_test.go
new file mode 100644
index 0000000..b5c2a74
--- /dev/null
+++ b/git/commit/git_list_all_commit_logs_test.go
@@ -0,0 +1,101 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/stub"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type ListAllCommitLogsTestSuite struct {
+	suite.Suite
+	mockController    *gomock.Controller
+	mockRepo          *mocks.MockRepository
+	mockRevWalk       *mocks.MockRevWalk
+	repo              middleware.Repository
+	totalCommits      Total
+	listAllCommitLogs ListAllLogs
+}
+
+func TestListAllCommitLogsTestSuite(t *testing.T) {
+	suite.Run(t, new(ListAllCommitLogsTestSuite))
+}
+
+func (suite *ListAllCommitLogsTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRevWalk = mocks.NewMockRevWalk(suite.mockController)
+
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.listAllCommitLogs = NewListAllLogs(suite.mockRepo, nil, nil)
+	suite.totalCommits = NewTotalCommits(NewListAllLogs(suite.repo, nil, nil))
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnCommitLogs() {
+	suite.listAllCommitLogs = NewListAllLogs(suite.repo, nil, nil)
+	got, err := suite.listAllCommitLogs.Get()
+
+	suite.NotZero(len(got))
+	suite.Nil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenLogLimitIsGiven_ShouldReturnCommitLogsUptoLimit() {
+	var limit uint = 3
+
+	suite.listAllCommitLogs = NewListAllLogs(suite.repo, &limit, nil)
+	got, err := suite.listAllCommitLogs.Get()
+
+	suite.Equal(int(limit), len(got))
+	suite.Nil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenReferenceIsGiven_ShouldReturnCommitLogsAfterTheReference() {
+	var limit uint = 3
+
+	commits, _ := NewListAllLogs(suite.repo, &limit, nil).Get()
+	commitId, _ := git2go.NewOid(commits[limit-1].Id().String())
+	total := suite.totalCommits.Get()
+
+	suite.listAllCommitLogs = NewListAllLogs(suite.repo, nil, commitId)
+	got, err := suite.listAllCommitLogs.Get()
+	want := total - (int(limit) - 1)
+
+	suite.Equal(want, len(got))
+	suite.Nil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenRepoWalkFails_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Walk().Return(nil, errors.New("WALKER_ERROR"))
+
+	_, err := suite.listAllCommitLogs.Get()
+
+	suite.NotNil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenRepoHasNoCommits_ShouldReturnNoCommitLogs() {
+	suite.mockRepo.EXPECT().Walk().Return(stub.NewRevWalkStub(false), nil)
+
+	got, err := suite.listAllCommitLogs.Get()
+
+	suite.Zero(len(got))
+	suite.Nil(err)
+}
+
+func (suite *ListAllCommitLogsTestSuite) TestGet_WhenIteratorReturnsError_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Walk().Return(stub.NewRevWalkStub(true), nil)
+
+	_, err := suite.listAllCommitLogs.Get()
+
+	suite.NotNil(err)
+}
diff --git a/git/commit/git_total_commits.go b/git/commit/git_total_commits.go
new file mode 100644
index 0000000..5ab36ff
--- /dev/null
+++ b/git/commit/git_total_commits.go
@@ -0,0 +1,39 @@
+package commit
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Total interface {
+	Get() int
+}
+
+type totalCommits struct {
+	listAllLogs ListAllLogs
+}
+
+// Get function returns the total number of commits from the repo and commit message of the most recent commit
+func (t totalCommits) Get() int {
+	var total = 0
+	allLogs := t.listAllLogs
+
+	commits, err := allLogs.Get()
+	if err != nil {
+		logger.Log(fmt.Sprintf("Unable to obtain commits for the repo : %v", err.Error()), global.StatusError)
+		return total
+	}
+
+	total = len(commits)
+	if total == 0 {
+		logger.Log("Repo has no commit logs", global.StatusError)
+		return total
+	}
+
+	logger.Log(fmt.Sprintf("Total commits in the repo -> %v", total), global.StatusInfo)
+	return total
+}
+
+func NewTotalCommits(listAllLogs ListAllLogs) Total {
+	return totalCommits{listAllLogs: listAllLogs}
+}
diff --git a/git/commit/git_total_commits_test.go b/git/commit/git_total_commits_test.go
new file mode 100644
index 0000000..02df43e
--- /dev/null
+++ b/git/commit/git_total_commits_test.go
@@ -0,0 +1,72 @@
+package commit
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	commitMocks "github.com/neel1996/gitconvex/git/commit/mocks"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+type TotalCommitsTestSuite struct {
+	suite.Suite
+	mockController    *gomock.Controller
+	total             Total
+	repo              middleware.Repository
+	mockRepo          *mocks.MockRepository
+	mockWalker        *mocks.MockRevWalk
+	noHeadRepo        *git2go.Repository
+	mockAllCommitLogs *commitMocks.MockListAllLogs
+}
+
+func TestTotalCommitsTestSuite(t *testing.T) {
+	suite.Run(t, new(TotalCommitsTestSuite))
+}
+
+func (suite *TotalCommitsTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	noHeadPath := os.Getenv("GITCONVEX_TEST_REPO") + string(filepath.Separator) + "no_head"
+	noHeadRepo, _ := git2go.OpenRepository(noHeadPath)
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.repo = middleware.NewRepository(r)
+	suite.noHeadRepo = noHeadRepo
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockWalker = mocks.NewMockRevWalk(suite.mockController)
+	suite.mockAllCommitLogs = commitMocks.NewMockListAllLogs(suite.mockController)
+	suite.total = NewTotalCommits(suite.mockAllCommitLogs)
+}
+
+func (suite *TotalCommitsTestSuite) TestGet_WhenLogsAreAvailable_ShouldReturnTotal() {
+	suite.mockAllCommitLogs.EXPECT().Get().Return([]git2go.Commit{{}, {}}, nil)
+
+	got := suite.total.Get()
+
+	suite.NotZero(got)
+}
+
+func (suite *TotalCommitsTestSuite) TestGet_WhenListLogReturnsError_ShouldReturnZero() {
+	suite.mockAllCommitLogs.EXPECT().Get().Return(nil, errors.New("LIST_ERROR"))
+
+	got := suite.total.Get()
+
+	suite.Zero(got)
+}
+
+func (suite *TotalCommitsTestSuite) TestGet_WhenRepoHasNoCommits_ShouldReturnZero() {
+	suite.mockAllCommitLogs.EXPECT().Get().Return([]git2go.Commit{}, nil)
+
+	got := suite.total.Get()
+
+	suite.Zero(got)
+}
diff --git a/git/commit/mocks/mock_git_commit_file_history.go b/git/commit/mocks/mock_git_commit_file_history.go
new file mode 100644
index 0000000..575db0a
--- /dev/null
+++ b/git/commit/mocks/mock_git_commit_file_history.go
@@ -0,0 +1,51 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/commit/git_commit_file_history.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
+	model "github.com/neel1996/gitconvex/graph/model"
+)
+
+// MockFileHistory is a mock of FileHistory interface.
+type MockFileHistory struct {
+	ctrl     *gomock.Controller
+	recorder *MockFileHistoryMockRecorder
+}
+
+// MockFileHistoryMockRecorder is the mock recorder for MockFileHistory.
+type MockFileHistoryMockRecorder struct {
+	mock *MockFileHistory
+}
+
+// NewMockFileHistory creates a new mock instance.
+func NewMockFileHistory(ctrl *gomock.Controller) *MockFileHistory {
+	mock := &MockFileHistory{ctrl: ctrl}
+	mock.recorder = &MockFileHistoryMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockFileHistory) EXPECT() *MockFileHistoryMockRecorder {
+	return m.recorder
+}
+
+// Get mocks base method.
+func (m *MockFileHistory) Get(commit middleware.Commit) ([]*model.GitCommitFileResult, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get", commit)
+	ret0, _ := ret[0].([]*model.GitCommitFileResult)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockFileHistoryMockRecorder) Get(commit interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockFileHistory)(nil).Get), commit)
+}
diff --git a/git/commit/mocks/mock_git_list_all_commit_logs.go b/git/commit/mocks/mock_git_list_all_commit_logs.go
new file mode 100644
index 0000000..f0ac0ff
--- /dev/null
+++ b/git/commit/mocks/mock_git_list_all_commit_logs.go
@@ -0,0 +1,50 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/commit/git_list_all_commit_logs.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockListAllLogs is a mock of ListAllLogs interface.
+type MockListAllLogs struct {
+	ctrl     *gomock.Controller
+	recorder *MockListAllLogsMockRecorder
+}
+
+// MockListAllLogsMockRecorder is the mock recorder for MockListAllLogs.
+type MockListAllLogsMockRecorder struct {
+	mock *MockListAllLogs
+}
+
+// NewMockListAllLogs creates a new mock instance.
+func NewMockListAllLogs(ctrl *gomock.Controller) *MockListAllLogs {
+	mock := &MockListAllLogs{ctrl: ctrl}
+	mock.recorder = &MockListAllLogsMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockListAllLogs) EXPECT() *MockListAllLogsMockRecorder {
+	return m.recorder
+}
+
+// Get mocks base method.
+func (m *MockListAllLogs) Get() ([]git.Commit, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get")
+	ret0, _ := ret[0].([]git.Commit)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockListAllLogsMockRecorder) Get() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockListAllLogs)(nil).Get))
+}
diff --git a/git/commit/search/commit_author_search.go b/git/commit/search/commit_author_search.go
new file mode 100644
index 0000000..45ad4cf
--- /dev/null
+++ b/git/commit/search/commit_author_search.go
@@ -0,0 +1,40 @@
+package search
+
+import (
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"regexp"
+	"strings"
+)
+
+type commitAuthorSearch struct {
+	commits []git.Commit
+}
+
+func (h commitAuthorSearch) Search(searchKey string) []git.Commit {
+	var (
+		matchingCommits []git.Commit
+		counter         = 0
+	)
+
+	for _, commit := range h.commits {
+		if h.isExceedingSearchLimit(counter) {
+			break
+		}
+
+		if isMatch, _ := regexp.MatchString(h.toLower(searchKey), h.toLower(commit.Author().Name)); isMatch {
+			matchingCommits = append(matchingCommits, commit)
+			counter++
+		}
+	}
+
+	return matchingCommits
+}
+
+func (h commitAuthorSearch) toLower(value string) string {
+	return strings.ToLower(strings.TrimSpace(value))
+}
+
+func (h commitAuthorSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
+	return searchLimitCounter == constants.SearchLimit
+}
diff --git a/git/commit/search/commit_author_search_test.go b/git/commit/search/commit_author_search_test.go
new file mode 100644
index 0000000..a6967b0
--- /dev/null
+++ b/git/commit/search/commit_author_search_test.go
@@ -0,0 +1,37 @@
+package search
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/search/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitAuthorSearchTestSuite struct {
+	suite.Suite
+	search     Search
+	allCommits []git2go.Commit
+}
+
+func TestCommitAuthorSearchTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitAuthorSearchTestSuite))
+}
+
+func (suite *CommitAuthorSearchTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	repo := middleware.NewRepository(r)
+	suite.allCommits = test_utils.GetAllTestCommitLogs(repo)
+	suite.search = GetSearchAction("author", suite.allCommits)
+}
+
+func (suite *CommitAuthorSearchTestSuite) TestSearch_WhenCommitHasMatchingAuthor_ShouldReturnCommits() {
+	commits := suite.search.Search("test")
+
+	suite.NotZero(len(commits))
+}
diff --git a/git/commit/search/commit_hash_search.go b/git/commit/search/commit_hash_search.go
new file mode 100644
index 0000000..ed95335
--- /dev/null
+++ b/git/commit/search/commit_hash_search.go
@@ -0,0 +1,35 @@
+package search
+
+import (
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"regexp"
+)
+
+type commitHashSearch struct {
+	commits []git.Commit
+}
+
+func (h commitHashSearch) Search(searchKey string) []git.Commit {
+	var (
+		matchingCommits []git.Commit
+		counter         = 0
+	)
+
+	for _, commit := range h.commits {
+		if h.isExceedingSearchLimit(counter) {
+			break
+		}
+
+		if isMatch, _ := regexp.MatchString(searchKey, commit.Id().String()); isMatch {
+			matchingCommits = append(matchingCommits, commit)
+			counter++
+		}
+	}
+
+	return matchingCommits
+}
+
+func (h commitHashSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
+	return searchLimitCounter == constants.SearchLimit
+}
diff --git a/git/commit/search/commit_hash_search_test.go b/git/commit/search/commit_hash_search_test.go
new file mode 100644
index 0000000..37fa2f0
--- /dev/null
+++ b/git/commit/search/commit_hash_search_test.go
@@ -0,0 +1,37 @@
+package search
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/search/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitHashSearchTestSuite struct {
+	suite.Suite
+	search     Search
+	allCommits []git2go.Commit
+}
+
+func TestCommitHashSearchTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitHashSearchTestSuite))
+}
+
+func (suite *CommitHashSearchTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	repo := middleware.NewRepository(r)
+	suite.allCommits = test_utils.GetAllTestCommitLogs(repo)
+	suite.search = GetSearchAction("hash", suite.allCommits)
+}
+
+func (suite *CommitHashSearchTestSuite) TestSearch_ShouldReturnCommitsMatchingHash() {
+	commits := suite.search.Search("0")
+
+	suite.NotZero(len(commits))
+}
diff --git a/git/commit/search/commit_message_search.go b/git/commit/search/commit_message_search.go
new file mode 100644
index 0000000..853f1cf
--- /dev/null
+++ b/git/commit/search/commit_message_search.go
@@ -0,0 +1,40 @@
+package search
+
+import (
+	git "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"regexp"
+	"strings"
+)
+
+type commitMessageSearch struct {
+	commits []git.Commit
+}
+
+func (m commitMessageSearch) Search(searchKey string) []git.Commit {
+	var (
+		matchingCommits []git.Commit
+		counter         = 0
+	)
+
+	for _, commit := range m.commits {
+		if m.isExceedingSearchLimit(counter) {
+			break
+		}
+
+		if isMatch, _ := regexp.MatchString(m.toLower(searchKey), m.toLower(commit.Message())); isMatch {
+			matchingCommits = append(matchingCommits, commit)
+			counter++
+		}
+	}
+
+	return matchingCommits
+}
+
+func (m commitMessageSearch) toLower(value string) string {
+	return strings.ToLower(strings.TrimSpace(value))
+}
+
+func (m commitMessageSearch) isExceedingSearchLimit(searchLimitCounter int) bool {
+	return searchLimitCounter == constants.SearchLimit
+}
diff --git a/git/commit/search/commit_message_search_test.go b/git/commit/search/commit_message_search_test.go
new file mode 100644
index 0000000..2551ac7
--- /dev/null
+++ b/git/commit/search/commit_message_search_test.go
@@ -0,0 +1,37 @@
+package search
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/commit/search/test_utils"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type CommitMessageSearchTestSuite struct {
+	suite.Suite
+	allCommits []git2go.Commit
+	search     Search
+}
+
+func TestCommitMessageSearchTestSuite(t *testing.T) {
+	suite.Run(t, new(CommitMessageSearchTestSuite))
+}
+
+func (suite *CommitMessageSearchTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	repo := middleware.NewRepository(r)
+	suite.allCommits = test_utils.GetAllTestCommitLogs(repo)
+	suite.search = GetSearchAction("message", suite.allCommits)
+}
+
+func (suite *CommitMessageSearchTestSuite) TestSearch_ShouldReturnCommitsMatchingTheMessage() {
+	commits := suite.search.Search("")
+
+	suite.NotZero(len(commits))
+}
diff --git a/git/commit/search/search.go b/git/commit/search/search.go
new file mode 100644
index 0000000..549600b
--- /dev/null
+++ b/git/commit/search/search.go
@@ -0,0 +1,9 @@
+package search
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+)
+
+type Search interface {
+	Search(string) []git2go.Commit
+}
diff --git a/git/commit/search/search_factory.go b/git/commit/search/search_factory.go
new file mode 100644
index 0000000..be6a261
--- /dev/null
+++ b/git/commit/search/search_factory.go
@@ -0,0 +1,40 @@
+package search
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+)
+
+type Type int
+
+const (
+	CommitHash = iota + 1
+	CommitMessage
+	CommitAuthor
+)
+
+var typeMap = map[string]Type{
+	"hash":    CommitHash,
+	"message": CommitMessage,
+	"author":  CommitAuthor,
+}
+
+func GetSearchAction(searchType string, commits []git2go.Commit) Search {
+	mappedSearchType := typeMap[searchType]
+
+	switch mappedSearchType {
+	case CommitHash:
+		return commitHashSearch{
+			commits: commits,
+		}
+	case CommitMessage:
+		return commitMessageSearch{
+			commits: commits,
+		}
+	case CommitAuthor:
+		return commitAuthorSearch{
+			commits: commits,
+		}
+	default:
+		return nil
+	}
+}
diff --git a/git/commit/search/search_factory_test.go b/git/commit/search/search_factory_test.go
new file mode 100644
index 0000000..21ecd8f
--- /dev/null
+++ b/git/commit/search/search_factory_test.go
@@ -0,0 +1,39 @@
+package search
+
+import (
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type SearchFactoryTestSuite struct {
+	suite.Suite
+}
+
+func TestSearchFactoryTestSuite(t *testing.T) {
+	suite.Run(t, new(SearchFactoryTestSuite))
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_ShouldReturnCommitHashSearchAction() {
+	action := GetSearchAction("hash", []git2go.Commit{})
+
+	suite.IsType(commitHashSearch{}, action)
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_ShouldReturnCommitAuthorSearchAction() {
+	action := GetSearchAction("author", []git2go.Commit{})
+
+	suite.IsType(commitAuthorSearch{}, action)
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_ShouldReturnCommitMessageSearchAction() {
+	action := GetSearchAction("message", []git2go.Commit{})
+
+	suite.IsType(commitMessageSearch{}, action)
+}
+
+func (suite *SearchFactoryTestSuite) TestGetSearchAction_WhenTypeIsInvalid_ShouldReturnNil() {
+	action := GetSearchAction("invalid", []git2go.Commit{})
+
+	suite.Nil(action)
+}
diff --git a/git/commit/search/test_utils/commit_log_util.go b/git/commit/search/test_utils/commit_log_util.go
new file mode 100644
index 0000000..a6c9fbf
--- /dev/null
+++ b/git/commit/search/test_utils/commit_log_util.go
@@ -0,0 +1,25 @@
+package test_utils
+
+import (
+	"fmt"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+func GetAllTestCommitLogs(repo middleware.Repository) []git2go.Commit {
+	var commits []git2go.Commit
+
+	logItr, _ := repo.Walk()
+
+	err := logItr.PushHead()
+	err = logItr.Iterate(func(commit *git2go.Commit) bool {
+		if commit != nil {
+			commits = append(commits, *commit)
+			return true
+		}
+		return false
+	})
+
+	fmt.Println(err)
+	return commits
+}
diff --git a/git/commit/stub/git_list_all_commit_logs_test_stub.go b/git/commit/stub/git_list_all_commit_logs_test_stub.go
new file mode 100644
index 0000000..6518b21
--- /dev/null
+++ b/git/commit/stub/git_list_all_commit_logs_test_stub.go
@@ -0,0 +1,31 @@
+package stub
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+type revWalkStub struct {
+	walk                     *git2go.RevWalk
+	shouldIterateReturnError bool
+}
+
+func (w *revWalkStub) Push(id *git2go.Oid) error {
+	return nil
+}
+
+func (w *revWalkStub) PushHead() error {
+	return nil
+}
+
+func (w *revWalkStub) Iterate(iterator git2go.RevWalkIterator) error {
+	if w.shouldIterateReturnError {
+		return errors.New("ITERATE_ERROR")
+	}
+	return nil
+}
+
+func NewRevWalkStub(shouldIterateReturnError bool) middleware.RevWalk {
+	return &revWalkStub{walk: &git2go.RevWalk{}, shouldIterateReturnError: shouldIterateReturnError}
+}
diff --git a/git/git_branch_add.go b/git/git_branch_add.go
deleted file mode 100644
index a16e63e..0000000
--- a/git/git_branch_add.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-)
-
-type AddBranch interface {
-	AddBranch() string
-}
-
-type addBranch struct {
-	Repo         *git2go.Repository
-	BranchName   string
-	RemoteSwitch bool
-	TargetCommit *git2go.Commit
-}
-
-// AddBranch adds a new branch to the target repo
-func (a addBranch) AddBranch() string {
-	targetCommit := a.TargetCommit
-	repo := a.Repo
-	branchName := a.BranchName
-	head, headErr := repo.Head()
-
-	logger.Log(fmt.Sprintf("Adding new branch -> %s", branchName), global.StatusInfo)
-	if headErr != nil {
-		logger.Log(fmt.Sprintf("Unable to fetch HEAD -> %s", headErr.Error()), global.StatusError)
-		return global.BranchAddError
-	}
-
-	targetCommit, hasValidationErr := a.validateTargetCommit(targetCommit, repo, head)
-	if hasValidationErr {
-		return global.BranchAddError
-	}
-
-	_, branchErr := repo.CreateBranch(branchName, targetCommit, false)
-	if branchErr != nil {
-		logger.Log(fmt.Sprintf("Failed to add branch - %s - %s", branchName, branchErr.Error()), global.StatusError)
-		return global.BranchAddError
-	}
-
-	logger.Log(fmt.Sprintf("Added new branch - %s to the repo", branchName), global.StatusInfo)
-	return global.BranchAddSuccess
-}
-
-func (a addBranch) validateTargetCommit(targetCommit *git2go.Commit, repo *git2go.Repository, head *git2go.Reference) (*git2go.Commit, bool) {
-	if targetCommit != nil {
-		return targetCommit, false
-	}
-
-	headCommit, _ := repo.LookupCommit(head.Target())
-	if headCommit == nil {
-		return nil, true
-	}
-
-	return headCommit, false
-}
-
-func NewAddBranch(repo *git2go.Repository, branchName string, remoteSwitch bool, targetCommit *git2go.Commit) AddBranch {
-	return addBranch{
-		Repo:         repo,
-		BranchName:   branchName,
-		RemoteSwitch: remoteSwitch,
-		TargetCommit: targetCommit,
-	}
-}
diff --git a/git/git_branch_checkout.go b/git/git_branch_checkout.go
deleted file mode 100644
index 9c1e8be..0000000
--- a/git/git_branch_checkout.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"go/types"
-	"strings"
-)
-
-type BranchCheckoutInterface interface {
-	CheckoutBranch() string
-}
-
-type BranchCheckoutInputs struct {
-	Repo       *git2go.Repository
-	BranchName string
-}
-
-func returnCheckoutError(err error) string {
-	logger.Log(err.Error(), global.StatusError)
-	return global.BranchCheckoutError
-}
-
-func checkCheckoutError(err error) bool {
-	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		panic(err)
-		return true
-	}
-	return false
-}
-
-// CheckoutBranch checks out the branchName received as argument
-func (inputs BranchCheckoutInputs) CheckoutBranch() string {
-	var isRemoteBranch bool
-	var referenceBranchName string
-	var remoteBranchName string
-	var errStatus bool
-
-	defer func() string {
-		if r := recover(); r != nil {
-			logger.Log(fmt.Sprintf("%v", r), global.StatusError)
-			return global.BranchCheckoutError
-		}
-		return global.BranchCheckoutError
-	}()
-
-	repo := inputs.Repo
-	branchName := inputs.BranchName
-
-	if strings.Contains(branchName, "remotes/") {
-		singleBranchName := strings.Split(branchName, "/")
-		referenceBranchName = "refs/heads/" + singleBranchName[len(singleBranchName)-1]
-		remoteBranchSplit := strings.Split(branchName, "remotes/")
-		remoteBranchName = remoteBranchSplit[len(remoteBranchSplit)-1]
-		branchName = singleBranchName[len(singleBranchName)-1]
-		isRemoteBranch = true
-	} else {
-		referenceBranchName = "refs/heads/" + branchName
-	}
-
-	if isRemoteBranch {
-		logger.Log(fmt.Sprintf("Branch - %s is a remote branch. Trying with intermediate remote fetch!", branchName), global.StatusWarning)
-
-		remoteBranch, remoteBranchErr := repo.LookupBranch(remoteBranchName, git2go.BranchRemote)
-		errStatus = checkCheckoutError(remoteBranchErr)
-
-		remoteHead := remoteBranch.Target()
-
-		remoteCommit, remoteCommitErr := repo.LookupCommit(remoteHead)
-		errStatus = checkCheckoutError(remoteCommitErr)
-
-		remoteTree, remoteTreeErr := remoteCommit.Tree()
-		errStatus = checkCheckoutError(remoteTreeErr)
-
-		checkoutErr := repo.CheckoutTree(remoteTree, &git2go.CheckoutOptions{Strategy: git2go.CheckoutSafe})
-		errStatus = checkCheckoutError(checkoutErr)
-
-		_, localLookupErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-		if localLookupErr != nil {
-			logger.Log(localLookupErr.Error(), global.StatusError)
-
-			var addBranch AddBranch
-			addBranch = NewAddBranch(repo, branchName, false, remoteCommit)
-
-			branchCreateStatus := addBranch.AddBranch()
-			if branchCreateStatus != global.BranchAddError {
-				err := repo.SetHead(referenceBranchName)
-				if err != nil {
-					return returnCheckoutError(err)
-				} else {
-					return fmt.Sprintf("Head checked out to branch - %v", branchName)
-				}
-			} else {
-				return returnCheckoutError(types.Error{Msg: "Branch creation failed"})
-			}
-		} else {
-			err := repo.SetHead(referenceBranchName)
-			if err != nil {
-				return returnCheckoutError(err)
-			} else {
-				return fmt.Sprintf("Head checked out to branch - %v", branchName)
-			}
-		}
-	}
-
-	branch, branchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-	errStatus = checkCheckoutError(branchErr)
-
-	topCommit, _ := repo.LookupCommit(branch.Target())
-	if topCommit != nil {
-		tree, treeErr := topCommit.Tree()
-		errStatus = checkCheckoutError(treeErr)
-
-		checkoutErr := repo.CheckoutTree(tree, &git2go.CheckoutOptions{
-			Strategy:       git2go.CheckoutSafe,
-			DisableFilters: false,
-		})
-
-		if checkoutErr != nil {
-			return returnCheckoutError(checkoutErr)
-		}
-
-		err := repo.SetHead(referenceBranchName)
-		if err != nil {
-			return returnCheckoutError(err)
-		}
-	}
-
-	if errStatus {
-		return global.BranchCheckoutError
-	} else {
-		logger.Log(fmt.Sprintf("Current branch checked out to -> %s", branchName), global.StatusInfo)
-		return fmt.Sprintf("Head checked out to branch - %v", branchName)
-	}
-}
diff --git a/git/git_branch_compare.go b/git/git_branch_compare.go
deleted file mode 100644
index f16cf0f..0000000
--- a/git/git_branch_compare.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package git
-
-import (
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"sort"
-	"strings"
-)
-
-type BranchCompareInterface interface {
-	CompareBranch() []*model.BranchCompareResults
-}
-
-type BranchCompareInputs struct {
-	Repo       *git2go.Repository
-	BaseBranch string
-	DiffBranch string
-}
-
-func returnBranchCompareError(errString string) []*model.BranchCompareResults {
-	if errString != "" {
-		logger.Log(errString, global.StatusWarning)
-		return []*model.BranchCompareResults{}
-	}
-	return nil
-}
-
-// CompareBranch compares two branches and returns the commits which are different from each other
-// The function uses the git client to fetch the results as go-git lacks this feature
-func (inputs BranchCompareInputs) CompareBranch() []*model.BranchCompareResults {
-	var diffCommits []*model.BranchCompareResults
-	var commits []model.GitCommits
-	repo := inputs.Repo
-
-	baseBranch, baseBranchErr := repo.LookupBranch(inputs.BaseBranch, git2go.BranchLocal)
-	compareBranch, compareBranchErr := repo.LookupBranch(inputs.DiffBranch, git2go.BranchLocal)
-
-	if baseBranchErr != nil || compareBranchErr != nil {
-		return returnBranchCompareError("Unable to lookup target branches from the repo")
-	}
-	compareResult := baseBranch.Cmp(compareBranch.Reference)
-
-	if compareResult == 0 {
-		return returnBranchCompareError("There are no difference between both the branches")
-	}
-
-	baseTarget := baseBranch.Target()
-	compareTarget := compareBranch.Target()
-
-	baseHead, _ := repo.LookupCommit(baseTarget)
-	compareHead, _ := repo.LookupCommit(compareTarget)
-
-	if baseHead == nil || compareHead == nil {
-		return returnBranchCompareError("Branch head is NIL")
-	}
-
-	var baseNext *git2go.Commit
-	var compareNext *git2go.Commit
-	baseBranchMap := make(map[string]*git2go.Commit)
-	compareBranchMap := make(map[string]*git2go.Commit)
-
-	if baseHead.ParentCount() > 0 {
-		baseNext = baseHead.Parent(0)
-		for baseNext != nil {
-			baseBranchMap[baseNext.Id().String()] = baseNext
-			baseNext = baseNext.Parent(0)
-		}
-	}
-
-	if compareHead.ParentCount() > 0 {
-		compareNext = compareHead.Parent(0)
-		for compareNext != nil {
-			compareBranchMap[compareNext.Id().String()] = compareNext
-			compareNext = compareNext.Parent(0)
-		}
-	}
-
-	for commitHash, commit := range compareBranchMap {
-		if baseBranchMap[commitHash] == nil {
-			hash := commit.Id().String()
-			author := commit.Author().Name
-			commitTime := strings.Split(commit.Author().When.String(), " ")[0]
-			message := commit.Message()
-
-			commits = append(commits, model.GitCommits{
-				Hash:          &hash,
-				Author:        &author,
-				CommitTime:    &commitTime,
-				CommitMessage: &message,
-			})
-		}
-	}
-
-	// Organizing differing commits based on date
-	var commitMap = make(map[string][]*model.GitCommits)
-	var tempCommitHashMap = make(map[string]bool)
-
-	for i := range commits {
-		selectedDate := *commits[i].CommitTime
-
-		j := i
-		for j < len(commits) {
-			if selectedDate == *commits[j].CommitTime {
-				if len(tempCommitHashMap) > 0 && tempCommitHashMap[*commits[j].Hash] {
-					break
-				}
-				if commitMap[selectedDate] != nil {
-					tempCommit := commitMap[selectedDate]
-					tempCommit = append(tempCommit, &commits[j])
-					commitMap[selectedDate] = tempCommit
-					tempCommitHashMap[*commits[j].Hash] = true
-				} else {
-					tempCommit := []*model.GitCommits{&commits[j]}
-					commitMap[selectedDate] = tempCommit
-					tempCommitHashMap[*commits[j].Hash] = true
-				}
-			} else {
-				break
-			}
-			j++
-		}
-	}
-
-	// Sorting commits in reverse chronological order of date
-	var keys []string
-	for k := range commitMap {
-		keys = append(keys, k)
-	}
-	sort.Strings(keys)
-	sort.Sort(sort.Reverse(sort.StringSlice(keys)))
-
-	// Extracting differing commits to the resultant model
-	for _, date := range keys {
-		diffCommits = append(diffCommits, &model.BranchCompareResults{
-			Date:    date,
-			Commits: commitMap[date],
-		})
-	}
-
-	return diffCommits
-}
diff --git a/git/git_branch_delete.go b/git/git_branch_delete.go
deleted file mode 100644
index b311674..0000000
--- a/git/git_branch_delete.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type DeleteBranchInterface interface {
-	DeleteBranch() *model.BranchDeleteStatus
-}
-
-type DeleteBranchInputs struct {
-	Repo       *git2go.Repository
-	BranchName string
-}
-
-// DeleteBranch deletes a branch from the repo
-func (inputs DeleteBranchInputs) DeleteBranch() *model.BranchDeleteStatus {
-	repo := inputs.Repo
-	branchName := inputs.BranchName
-	deleteBranch, deleteBranchErr := repo.LookupBranch(branchName, git2go.BranchLocal)
-
-	if deleteBranchErr != nil {
-		logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteBranchErr.Error()), global.StatusError)
-		return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
-	} else {
-		deleteErr := deleteBranch.Delete()
-		if deleteErr == nil {
-			logger.Log(fmt.Sprintf("Branch - %s has been removed from the repo", branchName), global.StatusInfo)
-			return &model.BranchDeleteStatus{
-				Status: global.BranchDeleteSuccess,
-			}
-		} else {
-			logger.Log(fmt.Sprintf("Failed to delete branch %s -> %v", branchName, deleteErr.Error()), global.StatusError)
-			return &model.BranchDeleteStatus{Status: global.BranchDeleteError}
-		}
-	}
-}
diff --git a/git/git_branch_list.go b/git/git_branch_list.go
deleted file mode 100644
index 69acba1..0000000
--- a/git/git_branch_list.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"go/types"
-	"strings"
-)
-
-type BranchListInterface interface {
-	GetBranchList(branchChan chan Branch)
-}
-
-type BranchListInputs struct {
-	Repo *git2go.Repository
-}
-
-type Branch struct {
-	CurrentBranch string
-	BranchList    []*string
-	AllBranchList []*string
-}
-
-// GetBranchList fetches all the branches from the target repository
-// The result will be returned as a struct with the current branch and all the available branches
-func (inputs BranchListInputs) GetBranchList(branchChan chan Branch) {
-	var (
-		branches      []*string
-		allBranchList []*string
-	)
-	var currentBranch string
-	repo := inputs.Repo
-
-	if repo != nil {
-		head, headErr := repo.Head()
-
-		if headErr != nil {
-			logger.Log(fmt.Sprintf("Repo head is invalid -> %s", headErr.Error()), global.StatusError)
-			nilMsg := []string{"No Branches available", "Repo HEAD is nil", "No Branches Present"}
-			branchChan <- Branch{
-				BranchList:    []*string{&nilMsg[0]},
-				CurrentBranch: nilMsg[1],
-				AllBranchList: []*string{&nilMsg[2]},
-			}
-		} else {
-			currentBranch = head.Name()
-			splitCurrentBranch := strings.Split(currentBranch, "/")
-			currentBranch = splitCurrentBranch[len(splitCurrentBranch)-1]
-
-			allBranchList = append(allBranchList, &currentBranch)
-			branches = append(branches, &currentBranch)
-
-			localBranchIterator, itrErr := repo.NewBranchIterator(git2go.BranchAll)
-
-			if itrErr == nil {
-				_ = localBranchIterator.ForEach(func(branch *git2go.Branch, branchType git2go.BranchType) error {
-					branchName, nameErr := branch.Name()
-					if branch == nil {
-						return types.Error{Msg: "branch iterator end"}
-					}
-					if nameErr == nil && !branch.IsTag() && !branch.IsNote() && branchName != currentBranch {
-						if branch.IsRemote() && strings.Contains(branchName, "/") {
-							splitString := strings.Split(branchName, "/")
-							splitBranch := splitString[len(splitString)-1]
-							if splitBranch != "HEAD" && splitBranch != currentBranch {
-								concatRemote := "remotes/" + strings.Join(splitString, "/")
-								allBranchList = append(allBranchList, &concatRemote)
-							}
-						} else {
-							allBranchList = append(allBranchList, &branchName)
-							branches = append(branches, &branchName)
-						}
-					}
-					return nil
-				})
-			}
-			branchChan <- Branch{
-				BranchList:    branches,
-				CurrentBranch: currentBranch,
-				AllBranchList: allBranchList,
-			}
-		}
-	}
-	close(branchChan)
-}
diff --git a/git/git_commit_changes.go b/git/git_commit_changes.go
deleted file mode 100644
index f6fb1c3..0000000
--- a/git/git_commit_changes.go
+++ /dev/null
@@ -1,107 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"runtime/debug"
-	"strings"
-)
-
-type CommitInterface interface {
-	CommitChanges() string
-}
-
-type CommitStruct struct {
-	Repo          *git2go.Repository
-	CommitMessage string
-	RepoPath      string
-}
-
-func checkCommitError(err error) bool {
-	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		panic(err)
-		return true
-	}
-	return false
-}
-
-// CommitChanges commits the staged changes to the repo
-// Rewrites the repo index tree with the staged files to commit the changes
-func (c CommitStruct) CommitChanges() string {
-	var errStatus bool
-	var headCommit *git2go.Commit
-
-	commitMessage := c.CommitMessage
-	repo := c.Repo
-
-	defer func() string {
-		if r := recover(); r != nil {
-			logger.Log(string(debug.Stack()), global.StatusError)
-			return global.CommitChangeError
-		}
-		return ""
-	}()
-
-	var formattedMessage = commitMessage
-	signature, signatureErr := repo.DefaultSignature()
-
-	if signatureErr != nil {
-		logger.Log(fmt.Sprintf("Error occurred while fetching repo signature -> %s", signatureErr.Error()), global.StatusError)
-		logger.Log("Setup you user name and email using `git config user.name and git config user.email`", global.StatusWarning)
-		return global.CommitChangeError
-	}
-
-	if strings.Contains(commitMessage, "||") {
-		splitMessage := strings.Split(commitMessage, "||")
-		formattedMessage = strings.Join(splitMessage, "\n")
-	}
-
-	head, headErr := repo.Head()
-	if headErr != nil {
-		logger.Log("Repo has no HEAD. Proceeding with a NIL HEAD", global.StatusWarning)
-		headCommit = nil
-	} else {
-		var headCommitErr error
-		headCommit, headCommitErr = repo.LookupCommit(head.Target())
-		errStatus = checkCommitError(headCommitErr)
-	}
-
-	repoIndex, indexErr := repo.Index()
-	errStatus = checkCommitError(indexErr)
-
-	newTreeId, writeTreeErr := repoIndex.WriteTree()
-	errStatus = checkCommitError(writeTreeErr)
-
-	newTree, newTreeErr := repo.LookupTree(newTreeId)
-	errStatus = checkCommitError(newTreeErr)
-
-	var (
-		newCommitId    *git2go.Oid
-		newCommitIdErr error
-	)
-	if headErr != nil {
-		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree)
-	} else {
-		newCommitId, newCommitIdErr = repo.CreateCommit("HEAD", signature, signature, formattedMessage, newTree, headCommit)
-	}
-	errStatus = checkCommitError(newCommitIdErr)
-
-	_, newCommitErr := repo.LookupCommit(newCommitId)
-	errStatus = checkCommitError(newCommitErr)
-
-	head, headErr = repo.Head()
-	errStatus = checkCommitError(headErr)
-
-	newRef, newRefErr := head.SetTarget(newCommitId, formattedMessage)
-	errStatus = checkCommitError(newRefErr)
-
-	if errStatus {
-		return global.CommitChangeError
-	} else {
-		logger.Log(fmt.Sprintf("New commit %s created", newCommitId.String()), global.StatusInfo)
-		logger.Log(newRef.Name(), global.StatusInfo)
-		return global.CommitChangeSuccess
-	}
-}
diff --git a/git/git_commit_files.go b/git/git_commit_files.go
deleted file mode 100644
index b4dde1a..0000000
--- a/git/git_commit_files.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type CommitFileListInterface interface {
-	CommitFileList() []*model.GitCommitFileResult
-}
-
-type CommitFileListStruct struct {
-	Repo       *git2go.Repository
-	CommitHash string
-}
-
-// Common function for returning empty response in case of errors
-func returnCommitFileError(err error) []*model.GitCommitFileResult {
-	logger.Log(err.Error(), global.StatusError)
-	return []*model.GitCommitFileResult{{
-		Type:     "",
-		FileName: "",
-	}}
-}
-
-// CommitFileList returns the list of files modified, added or removed as part of a commit
-// compares the previous commit tree with the current commit tree and, returns the change type (M|D|A) and file name
-func (c CommitFileListStruct) CommitFileList() []*model.GitCommitFileResult {
-	var res []*model.GitCommitFileResult
-
-	repo := c.Repo
-	commitHash := c.CommitHash
-
-	logger.Log(fmt.Sprintf("Fetching file details for commit %v", commitHash), global.StatusInfo)
-
-	oid, oidErr := git2go.NewOid(commitHash)
-	if oidErr != nil {
-		return returnCommitFileError(oidErr)
-	}
-
-	commit, err := repo.LookupCommit(oid)
-	if err != nil {
-		return returnCommitFileError(err)
-	}
-
-	numParents := commit.ParentCount()
-	if numParents > 0 {
-		prevCommit := commit.Parent(0)
-		prevTree, _ := prevCommit.Tree()
-		commitTree, _ := commit.Tree()
-
-		if commitTree != nil && prevTree != nil {
-			diff, diffErr := repo.DiffTreeToTree(prevTree, commitTree, nil)
-			if diffErr != nil {
-				return returnCommitFileError(diffErr)
-			}
-
-			numDelta, numDeltaErr := diff.NumDeltas()
-			if numDeltaErr != nil {
-				return returnCommitFileError(numDeltaErr)
-			}
-			for d := 0; d < numDelta; d++ {
-				delta, _ := diff.Delta(d)
-				status := delta.Status.String()
-				res = append(res, &model.GitCommitFileResult{
-					Type:     status[0:1],
-					FileName: delta.NewFile.Path,
-				})
-			}
-		}
-	} else {
-		return []*model.GitCommitFileResult{{
-			Type:     "",
-			FileName: "",
-		}}
-	}
-	return res
-}
diff --git a/git/git_commit_log_search.go b/git/git_commit_log_search.go
deleted file mode 100644
index ffde1dc..0000000
--- a/git/git_commit_log_search.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"regexp"
-)
-
-type SearchCommitInterface interface {
-	SearchCommitLogs() []*model.GitCommits
-}
-
-type SearchCommitStruct struct {
-	Repo       *git2go.Repository
-	SearchType string
-	SearchKey  string
-}
-
-// SearchCommitLogs searches for the required commits matching the searchKey with the respective searchType
-//
-// The UI uses 'message' as the default search type to look up based on commit messages
-func (s SearchCommitStruct) SearchCommitLogs() []*model.GitCommits {
-	var searchResult []*model.GitCommits
-
-	repo := s.Repo
-
-	searchKey := s.SearchKey
-	searchType := s.SearchType
-
-	walker, walkerErr := repo.Walk()
-
-	if walkerErr == nil {
-		logger.Log(fmt.Sprintf("Searching commit logs with %s for -> %s", searchType, searchKey), global.StatusInfo)
-		_ = walker.PushHead()
-		_ = walker.Iterate(func(commit *git2go.Commit) bool {
-			if len(searchResult) == 10 {
-				return false
-			}
-
-			switch searchType {
-			case "message":
-				if isMatch, _ := regexp.MatchString(searchKey, commit.Message()); isMatch {
-					commitLog := commitOrganizer(repo, []git2go.Commit{*commit})
-					searchResult = append(searchResult, commitLog...)
-				}
-				break
-			case "hash":
-				if isMatch, _ := regexp.MatchString(searchKey, commit.Id().String()); isMatch {
-					commitLog := commitOrganizer(repo, []git2go.Commit{*commit})
-					searchResult = append(searchResult, commitLog...)
-				}
-				break
-			case "user":
-				if isMatch, _ := regexp.MatchString(searchKey, commit.Author().Name); isMatch {
-					commitLog := commitOrganizer(repo, []git2go.Commit{*commit})
-					searchResult = append(searchResult, commitLog...)
-				}
-				break
-			}
-			return true
-		})
-	} else {
-		logger.Log(walkerErr.Error(), global.StatusError)
-		return searchResult
-	}
-	return searchResult
-}
diff --git a/git/git_commit_logs.go b/git/git_commit_logs.go
deleted file mode 100644
index 08db36a..0000000
--- a/git/git_commit_logs.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package git
-
-import (
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"strings"
-)
-
-type CommitLogInterface interface {
-	CommitLogs() *model.GitCommitLogResults
-}
-
-type CommitLogStruct struct {
-	Repo            *git2go.Repository
-	ReferenceCommit string
-}
-
-// commitOrganizer collects and organizes the commit related information in the GitCommits struct
-func commitOrganizer(repo *git2go.Repository, commits []git2go.Commit) []*model.GitCommits {
-	var commitList []*model.GitCommits
-	for _, commit := range commits {
-		if commit.Id().String() != "" {
-			commitHash := commit.Id().String()
-			commitAuthor := strings.Split(commit.Author().Name, " ")[0]
-			commitMessage := strings.Split(commit.Message(), "\n")[0]
-			commitDate := commit.Committer().When.String()
-
-			parentCommit := commit.Parent(0)
-			if parentCommit == nil {
-				logger.Log("NIL parent Commit encountered", global.StatusWarning)
-				commitList = append(commitList, &model.GitCommits{
-					Hash:          &commitHash,
-					Author:        &commitAuthor,
-					CommitTime:    &commitDate,
-					CommitMessage: &commitMessage,
-				})
-				continue
-			}
-			parentTree, _ := parentCommit.Tree()
-			currentTree, _ := commit.Tree()
-
-			commitFileCount := 0
-			if parentTree != nil && currentTree != nil {
-				diff, diffErr := repo.DiffTreeToTree(parentTree, currentTree, nil)
-
-				if diffErr == nil {
-					commitFileCount, _ = diff.NumDeltas()
-				} else {
-					logger.Log(diffErr.Error(), global.StatusError)
-				}
-			} else {
-				logger.Log("Unable to fetch commit tree", global.StatusError)
-			}
-
-			commitList = append(commitList, &model.GitCommits{
-				Hash:             &commitHash,
-				Author:           &commitAuthor,
-				CommitTime:       &commitDate,
-				CommitMessage:    &commitMessage,
-				CommitFilesCount: &commitFileCount,
-			})
-		}
-	}
-	return commitList
-}
-
-// CommitLogs fetches the structured commit logs list for the target repo
-// Limits the length of commits to 10 for a single function call
-// The referenceCommit is used as a reference to fetch the commits in a linear manner
-func (c CommitLogStruct) CommitLogs() *model.GitCommitLogResults {
-	var commitLogs []git2go.Commit
-
-	repo := c.Repo
-	referenceCommit := c.ReferenceCommit
-
-	allCommitChan := make(chan AllCommitData)
-
-	var allCommitsObject AllCommitInterface
-	allCommitsObject = AllCommitStruct{Repo: repo}
-	go allCommitsObject.AllCommits(allCommitChan)
-
-	acc := <-allCommitChan
-	totalCommits := acc.TotalCommits
-
-	var counter int
-	counter = 0
-
-	logItr, itrErr := repo.Walk()
-	if itrErr != nil {
-		logger.Log(itrErr.Error(), global.StatusError)
-		return &model.GitCommitLogResults{
-			TotalCommits: &totalCommits,
-			Commits:      nil,
-		}
-	}
-
-	if referenceCommit == "" {
-		head, _ := repo.Head()
-		if head != nil {
-			if pushErr := logItr.PushHead(); pushErr != nil {
-				logger.Log(pushErr.Error(), global.StatusError)
-				return &model.GitCommitLogResults{
-					TotalCommits: &totalCommits,
-					Commits:      nil,
-				}
-			}
-
-			_ = logItr.Iterate(func(commit *git2go.Commit) bool {
-				if counter <= 10 {
-					commitLogs = append(commitLogs, *commit)
-					counter++
-					return true
-				}
-				return false
-			})
-		} else {
-			logger.Log("Unable to fetch repo HEAD", global.StatusError)
-			return &model.GitCommitLogResults{
-				TotalCommits: &totalCommits,
-				Commits:      nil,
-			}
-		}
-	} else {
-		refId, _ := git2go.NewOid(referenceCommit)
-		refCommit, refCommitErr := repo.LookupCommit(refId)
-
-		if refCommitErr == nil {
-			if pushErr := logItr.Push(refCommit.Id()); pushErr != nil {
-				logger.Log(pushErr.Error(), global.StatusError)
-				return &model.GitCommitLogResults{
-					TotalCommits: &totalCommits,
-					Commits:      nil,
-				}
-			}
-
-			_ = logItr.Iterate(func(commit *git2go.Commit) bool {
-				if counter <= 10 {
-					commitLogs = append(commitLogs, *commit)
-					counter++
-					return true
-				}
-				return false
-			})
-		} else {
-			logger.Log(refCommitErr.Error(), global.StatusError)
-			return &model.GitCommitLogResults{
-				TotalCommits: &totalCommits,
-				Commits:      nil,
-			}
-		}
-	}
-
-	if len(commitLogs) == 0 {
-		return &model.GitCommitLogResults{
-			TotalCommits: &totalCommits,
-			Commits:      nil,
-		}
-	}
-
-	refinedCommits := commitOrganizer(repo, commitLogs)
-	return &model.GitCommitLogResults{
-		TotalCommits: &totalCommits,
-		Commits:      refinedCommits,
-	}
-}
diff --git a/git/git_fetch.go b/git/git_fetch.go
index a8f8ca7..12fbc16 100644
--- a/git/git_fetch.go
+++ b/git/git_fetch.go
@@ -28,16 +28,9 @@ type FetchStruct struct {
 // If the remoteBranch is empty, then a fetch is performed with no branch name (similar to `git fetch`)
 func (f FetchStruct) FetchFromRemote() *model.FetchResult {
 	repo := f.Repo
-	remoteURL := f.RemoteURL
 	remoteBranch := f.RemoteBranch
+	remoteName := f.RemoteName
 
-	var remoteDataObject RemoteDataInterface
-	remoteDataObject = RemoteDataStruct{
-		Repo:      repo,
-		RemoteURL: remoteURL,
-	}
-
-	remoteName := remoteDataObject.GetRemoteName()
 	localRefSpec := "+refs/heads/" + remoteBranch
 	targetRefPsec := "refs/remotes/" + remoteName + "/" + remoteBranch
 	targetRemote, _ := repo.Remotes.Lookup(remoteName)
diff --git a/git/git_pull.go b/git/git_pull.go
index b5ecb1c..17ac9a7 100644
--- a/git/git_pull.go
+++ b/git/git_pull.go
@@ -36,15 +36,8 @@ func returnPullErr(msg string) *model.PullResult {
 func (p PullStruct) PullFromRemote() *model.PullResult {
 	repo := p.Repo
 	remoteBranch := p.RemoteBranch
-	remoteURL := p.RemoteURL
+	remoteName := p.RemoteName
 
-	var remoteDataObject RemoteDataInterface
-	remoteDataObject = RemoteDataStruct{
-		Repo:      repo,
-		RemoteURL: remoteURL,
-	}
-
-	remoteName := remoteDataObject.GetRemoteName()
 	localRefSpec := "+refs/heads/" + remoteBranch
 	targetRefPsec := "refs/remotes/" + remoteName + "/" + remoteBranch
 	targetRemote, _ := repo.Remotes.Lookup(remoteName)
diff --git a/git/git_remote_add.go b/git/git_remote_add.go
deleted file mode 100644
index b3b3b84..0000000
--- a/git/git_remote_add.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type AddRemoteInterface interface {
-	AddRemote() *model.RemoteMutationResult
-}
-
-type AddRemoteStruct struct {
-	Repo       *git2go.Repository
-	RemoteName string
-	RemoteURL  string
-}
-
-// AddRemote adds a new remote to the target git repo
-func (a AddRemoteStruct) AddRemote() *model.RemoteMutationResult {
-	repo := a.Repo
-	remoteName := a.RemoteName
-	remoteURL := a.RemoteURL
-
-	remote, err := repo.Remotes.Create(remoteName, remoteURL)
-
-	if err == nil {
-		logger.Log(fmt.Sprintf("New remote %s added to the repo", remote.Name()), global.StatusInfo)
-		return &model.RemoteMutationResult{Status: global.RemoteAddSuccess}
-	} else {
-		logger.Log("Remote addition Failed -> "+err.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteAddError}
-	}
-}
diff --git a/git/git_remote_allremotedata.go b/git/git_remote_allremotedata.go
deleted file mode 100644
index 4118668..0000000
--- a/git/git_remote_allremotedata.go
+++ /dev/null
@@ -1,123 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"strings"
-)
-
-type RemoteDataInterface interface {
-	GetRemoteHost() *string
-	GetRemoteName() string
-	GetAllRemotes() []*model.RemoteDetails
-	RemoteData(remoteChan chan RemoteDataModel)
-}
-
-type RemoteDataStruct struct {
-	Repo      *git2go.Repository
-	RemoteURL string
-}
-
-type RemoteDataModel struct {
-	RemoteHost *string
-	RemoteURL  []*string
-}
-
-// GetRemoteHost returns the remote repository host name based on the remote URL
-// e.g. github.com/test.git => returns github
-func (r RemoteDataStruct) GetRemoteHost() *string {
-	remoteURL := r.RemoteURL
-	var remoteHostReference []string
-	remoteHostReference = []string{"github", "gitlab", "bitbucket", "azure", "codecommit"}
-
-	for _, host := range remoteHostReference {
-		if strings.Contains(remoteURL, host) {
-			return &host
-		}
-	}
-	return nil
-}
-
-// GetRemoteName function returns the name of the remote based on the supplied remote URL
-func (r RemoteDataStruct) GetRemoteName() string {
-	repo := r.Repo
-	remoteURL := r.RemoteURL
-	remoteList, _ := repo.Remotes.List()
-
-	for _, remoteEntry := range remoteList {
-		remoteCollection, _ := repo.Remotes.Lookup(remoteEntry)
-		if remoteCollection != nil {
-			url := remoteCollection.Url()
-			if url == remoteURL {
-				remoteName := remoteCollection.Name()
-				logger.Log(fmt.Sprintf("Remote Name - %s for the url - %s", remoteName, remoteURL), global.StatusInfo)
-				return remoteName
-			}
-		}
-	}
-	logger.Log(fmt.Sprintf("Unable to find a suitable remote entry for the url - %s", remoteURL), global.StatusError)
-	return ""
-}
-
-// RemoteData returns the remote host name and the remote URL of the target repo
-func (r RemoteDataStruct) RemoteData(remoteChan chan RemoteDataModel) {
-	var remoteURL []*string
-	repo := r.Repo
-
-	remotes, _ := repo.Remotes.List()
-
-	for _, i := range remotes {
-		remote, _ := repo.Remotes.Lookup(i)
-		if remote != nil {
-			url := remote.Url()
-			remoteURL = append(remoteURL, &url)
-		}
-	}
-
-	if len(remoteURL) == 0 {
-		nilRemote := "No Remote Host Available"
-		nilRemoteURL := ""
-		remoteChan <- RemoteDataModel{
-			RemoteHost: &nilRemote,
-			RemoteURL:  []*string{&nilRemoteURL},
-		}
-	} else {
-		r.RemoteURL = *remoteURL[0]
-		remoteChan <- RemoteDataModel{
-			RemoteHost: r.GetRemoteHost(),
-			RemoteURL:  remoteURL,
-		}
-	}
-	close(remoteChan)
-}
-
-// GetAllRemotes returns all the remotes and their corresponding URLs from the target repo
-func (r RemoteDataStruct) GetAllRemotes() []*model.RemoteDetails {
-	var allRemoteData []*model.RemoteDetails
-
-	repo := r.Repo
-	remoteList, remoteListErr := repo.Remotes.List()
-	if remoteListErr != nil {
-		logger.Log(remoteListErr.Error(), global.StatusError)
-		return nil
-	}
-
-	for _, remoteEntry := range remoteList {
-		if remoteEntry != "" {
-			remote, remoteErr := repo.Remotes.Lookup(remoteEntry)
-			if remoteErr != nil {
-				logger.Log(remoteErr.Error(), global.StatusError)
-				continue
-			}
-			data := model.RemoteDetails{
-				RemoteName: remote.Name(),
-				RemoteURL:  remote.Url(),
-			}
-			logger.Log(fmt.Sprintf("Remote data fetched => %+v", data), global.StatusInfo)
-			allRemoteData = append(allRemoteData, &data)
-		}
-	}
-	return allRemoteData
-}
diff --git a/git/git_remote_delete.go b/git/git_remote_delete.go
deleted file mode 100644
index f3768bf..0000000
--- a/git/git_remote_delete.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type DeleteRemoteInterface interface {
-	DeleteRemote() *model.RemoteMutationResult
-}
-
-type DeleteRemoteStruct struct {
-	Repo       *git2go.Repository
-	RemoteName string
-}
-
-func (d *DeleteRemoteStruct) DeleteRemote() *model.RemoteMutationResult {
-	repo := d.Repo
-	remoteToBeDeleted := d.RemoteName
-
-	remoteList, listErr := repo.Remotes.List()
-	if listErr != nil {
-		logger.Log(listErr.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteDeleteError}
-	}
-
-	for _, remoteEntry := range remoteList {
-		if remoteEntry == remoteToBeDeleted {
-			err := repo.Remotes.Delete(remoteEntry)
-			if err != nil {
-				logger.Log(err.Error(), global.StatusError)
-				return &model.RemoteMutationResult{Status: global.RemoteDeleteError}
-			} else {
-				logger.Log(fmt.Sprintf("The remote => %s deleted from repo", remoteToBeDeleted), global.StatusInfo)
-				return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}
-			}
-		}
-	}
-
-	logger.Log(fmt.Sprintf("Remote => %s cannot be found in the repo", remoteToBeDeleted), global.StatusError)
-	return &model.RemoteMutationResult{Status: global.RemoteDeleteError}
-}
diff --git a/git/git_remote_edit.go b/git/git_remote_edit.go
deleted file mode 100644
index 7ae4376..0000000
--- a/git/git_remote_edit.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-)
-
-type RemoteEditInterface interface {
-	EditRemoteUrl() *model.RemoteMutationResult
-}
-
-type RemoteEditStruct struct {
-	Repo          *git2go.Repository
-	RemoteName    string
-	NewRemoteName string
-	RemoteUrl     string
-}
-
-func (e RemoteEditStruct) EditRemoteUrl() *model.RemoteMutationResult {
-	repo := e.Repo
-	remoteName := e.RemoteName
-	remoteUrl := e.RemoteUrl
-
-	remoteCollection := repo.Remotes
-	_, listErr := remoteCollection.List()
-
-	if listErr != nil {
-		logger.Log(listErr.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteEditError}
-	}
-
-	err := repo.Remotes.SetUrl(remoteName, remoteUrl)
-
-	if err != nil {
-		logger.Log(err.Error(), global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteEditError}
-	} else {
-		logger.Log(fmt.Sprintf("New URL has been set for the remote -> %s", remoteName), global.StatusInfo)
-		return &model.RemoteMutationResult{Status: global.RemoteEditSuccess}
-	}
-}
diff --git a/git/git_repo_validate.go b/git/git_repo_validate.go
index 6d5e3e0..ca4a00f 100644
--- a/git/git_repo_validate.go
+++ b/git/git_repo_validate.go
@@ -1,23 +1,35 @@
 package git
 
 import (
+	"errors"
 	"fmt"
 	git2go "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/global"
-	"go/types"
 	"os"
 )
 
-// RepoValidator validates if the specified repoPath represents a valid git repo
-func RepoValidator(repoPath string) (string, error) {
+type RepoValidator interface {
+	ValidateRepoWithPath() error
+	ValidateGitRepository()
+}
+
+type repoValidator struct {
+	repoPath string
+	repo     *git2go.Repository
+}
+
+// ValidateRepoWithPath validates if the specified repoPath represents a valid git repo
+func (r repoValidator) ValidateRepoWithPath() error {
+	repoPath := r.repoPath
+
 	_, err := os.Open(fmt.Sprintf("%v/.git/", repoPath))
 	if err != nil {
-		return "", types.Error{Msg: "The selected folder is not a git repo"}
+		return errors.New("the selected folder is not a git repo")
 	}
 
 	repo, repoErr := git2go.OpenRepository(repoPath)
 	if repoErr != nil {
-		return "", types.Error{Msg: "The selected folder is not a valid git repo"}
+		return errors.New("the selected folder is not a valid git repo")
 	}
 
 	_, headErr := repo.Head()
@@ -25,5 +37,26 @@ func RepoValidator(repoPath string) (string, error) {
 		logger.Log(fmt.Sprintf("Mind that the repo has no HEAD and a fresh commit is required -> %s", headErr.Error()), global.StatusWarning)
 	}
 
-	return "Repo is valid!", nil
+	return nil
+}
+
+func (r repoValidator) ValidateGitRepository() {
+	repo := r.repo
+
+	defer func() {
+		if panicValue := recover(); panicValue != nil {
+			logger.Log(fmt.Sprintf("%v", panicValue), global.StatusError)
+		}
+	}()
+
+	if repo == nil {
+		panic(errors.New("repository is nil and cannot be used for performing the desired operation"))
+	}
+}
+
+func NewRepoValidator(repoPath string, repo *git2go.Repository) RepoValidator {
+	return repoValidator{
+		repoPath: repoPath,
+		repo:     repo,
+	}
 }
diff --git a/git/git_total_commits.go b/git/git_total_commits.go
deleted file mode 100644
index 583b031..0000000
--- a/git/git_total_commits.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package git
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	"github.com/neel1996/gitconvex/global"
-)
-
-type AllCommitInterface interface {
-	AllCommits(commitChan chan AllCommitData)
-}
-
-type AllCommitStruct struct {
-	Repo *git2go.Repository
-}
-
-type AllCommitData struct {
-	TotalCommits float64
-	LatestCommit string
-}
-
-// AllCommits function returns the total number of commits from the repo and commit message of the most recent commit
-func (t AllCommitStruct) AllCommits(commitChan chan AllCommitData) {
-	repo := t.Repo
-	logItr, itrErr := repo.Walk()
-	var commits []git2go.Commit
-
-	if itrErr != nil {
-		logger.Log(fmt.Sprintf("Repo has no logs -> %s", itrErr.Error()), global.StatusError)
-		commitChan <- AllCommitData{
-			TotalCommits: 0,
-			LatestCommit: "No Commits Available!",
-		}
-	} else {
-		_ = logItr.PushHead()
-
-		err := logItr.Iterate(func(commit *git2go.Commit) bool {
-			if commit != nil {
-				commits = append(commits, *commit)
-				return true
-			} else {
-				return false
-			}
-		})
-
-		if err != nil {
-			logger.Log(fmt.Sprintf("Unable to obtain commits for the repo"), global.StatusError)
-			commitChan <- AllCommitData{
-				TotalCommits: 0,
-				LatestCommit: "No Commits Available!",
-			}
-
-		} else {
-			logger.Log(fmt.Sprintf("Total commits in the repo -> %v", len(commits)), global.StatusInfo)
-
-			if len(commits) > 0 {
-				commitChan <- AllCommitData{
-					TotalCommits: float64(len(commits)),
-					LatestCommit: commits[0].Message(),
-				}
-			}
-		}
-	}
-	close(commitChan)
-}
diff --git a/git/middleware/branch.go b/git/middleware/branch.go
new file mode 100644
index 0000000..bf50278
--- /dev/null
+++ b/git/middleware/branch.go
@@ -0,0 +1,56 @@
+package middleware
+
+import git2go "github.com/libgit2/git2go/v31"
+
+type Branch interface {
+	Target() *git2go.Oid
+	Delete() error
+	Cmp(r Reference) int
+	Reference() Reference
+	IsRemote() bool
+	Name() (string, error)
+	IsTag() bool
+	IsNote() bool
+}
+
+type branch struct {
+	branch *git2go.Branch
+}
+
+func (b branch) IsNote() bool {
+	return b.branch.IsNote()
+}
+
+func (b branch) IsTag() bool {
+	return b.branch.IsTag()
+}
+
+func (b branch) Name() (string, error) {
+	return b.branch.Name()
+}
+
+func (b branch) IsRemote() bool {
+	return b.branch.IsRemote()
+}
+
+func (b branch) Reference() Reference {
+	return NewReference(b.branch.Reference)
+}
+
+func (b branch) Cmp(r Reference) int {
+	return b.branch.Cmp(r.GetGitReference())
+}
+
+func (b branch) Delete() error {
+	return b.branch.Delete()
+}
+
+func (b branch) Target() *git2go.Oid {
+	return b.branch.Target()
+}
+
+func NewBranch(gitBranch *git2go.Branch) Branch {
+	return branch{
+		branch: gitBranch,
+	}
+}
diff --git a/git/middleware/branch_iterator.go b/git/middleware/branch_iterator.go
new file mode 100644
index 0000000..7ec4c33
--- /dev/null
+++ b/git/middleware/branch_iterator.go
@@ -0,0 +1,19 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type BranchIterator interface {
+	ForEach(func(b *git.Branch, branchType git.BranchType) error) error
+}
+
+type branchIterator struct {
+	iterator *git.BranchIterator
+}
+
+func (b branchIterator) ForEach(f func(b *git.Branch, branchType git.BranchType) error) error {
+	return b.iterator.ForEach(f)
+}
+
+func NewBranchIterator(iterator *git.BranchIterator) BranchIterator {
+	return branchIterator{iterator: iterator}
+}
diff --git a/git/middleware/commit.go b/git/middleware/commit.go
new file mode 100644
index 0000000..198ae20
--- /dev/null
+++ b/git/middleware/commit.go
@@ -0,0 +1,54 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Commit interface {
+	ParentCount() uint
+	Id() *git.Oid
+	Parent(uint) Commit
+	Tree() (*git.Tree, error)
+	GetGitCommit() *git.Commit
+	Author() *git.Signature
+	Message() string
+}
+
+type commit struct {
+	gitCommit *git.Commit
+}
+
+func (c commit) Author() *git.Signature {
+	return c.gitCommit.Author()
+}
+
+func (c commit) Message() string {
+	return c.gitCommit.Message()
+}
+
+func (c commit) GetGitCommit() *git.Commit {
+	return c.gitCommit
+}
+
+func (c commit) Tree() (*git.Tree, error) {
+	return c.gitCommit.Tree()
+}
+
+func (c commit) Parent(i uint) Commit {
+	parent := c.gitCommit.Parent(i)
+	if parent == nil {
+		return nil
+	}
+
+	return NewCommit(parent)
+}
+
+func (c commit) Id() *git.Oid {
+	return c.gitCommit.Id()
+}
+
+func (c commit) ParentCount() uint {
+	return c.gitCommit.ParentCount()
+}
+
+func NewCommit(gitCommit *git.Commit) Commit {
+	return commit{gitCommit: gitCommit}
+}
diff --git a/git/middleware/index.go b/git/middleware/index.go
new file mode 100644
index 0000000..730cda0
--- /dev/null
+++ b/git/middleware/index.go
@@ -0,0 +1,19 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Index interface {
+	WriteTree() (*git.Oid, error)
+}
+
+type index struct {
+	idx *git.Index
+}
+
+func (i index) WriteTree() (*git.Oid, error) {
+	return i.idx.WriteTree()
+}
+
+func NewIndex(idx *git.Index) Index {
+	return index{idx: idx}
+}
diff --git a/git/middleware/reference.go b/git/middleware/reference.go
new file mode 100644
index 0000000..b6b032f
--- /dev/null
+++ b/git/middleware/reference.go
@@ -0,0 +1,34 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Reference interface {
+	GetGitReference() *git.Reference
+	Target() *git.Oid
+	SetTarget(id *git.Oid, message string) (*git.Reference, error)
+	Name() string
+}
+
+type reference struct {
+	ref *git.Reference
+}
+
+func (r reference) Name() string {
+	return r.ref.Name()
+}
+
+func (r reference) Target() *git.Oid {
+	return r.ref.Target()
+}
+
+func (r reference) SetTarget(id *git.Oid, message string) (*git.Reference, error) {
+	return r.ref.SetTarget(id, message)
+}
+
+func (r reference) GetGitReference() *git.Reference {
+	return r.ref
+}
+
+func NewReference(ref *git.Reference) Reference {
+	return reference{ref: ref}
+}
diff --git a/git/middleware/remotes.go b/git/middleware/remotes.go
new file mode 100644
index 0000000..9fab02a
--- /dev/null
+++ b/git/middleware/remotes.go
@@ -0,0 +1,46 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Remotes interface {
+	Create(string, string) (*git.Remote, error)
+	Get() git.RemoteCollection
+	Delete(string) error
+	List() ([]string, error)
+	SetUrl(string, string) error
+	Lookup(string) (*git.Remote, error)
+}
+
+type remotes struct {
+	git.RemoteCollection
+}
+
+func (r remotes) Create(name string, url string) (*git.Remote, error) {
+	return r.RemoteCollection.Create(name, url)
+}
+
+func (r remotes) Get() git.RemoteCollection {
+	return r.RemoteCollection
+}
+
+func (r remotes) Delete(name string) error {
+	return r.RemoteCollection.Delete(name)
+}
+
+func (r remotes) List() ([]string, error) {
+	return r.RemoteCollection.List()
+}
+
+func (r remotes) SetUrl(name string, url string) error {
+	return r.RemoteCollection.SetUrl(name, url)
+}
+
+func (r remotes) Lookup(name string) (*git.Remote, error) {
+	return r.RemoteCollection.Lookup(name)
+}
+
+func NewRemotes(remoteCollection git.RemoteCollection) Remotes {
+	return remotes{
+		RemoteCollection: remoteCollection,
+	}
+}
diff --git a/git/middleware/repository.go b/git/middleware/repository.go
new file mode 100644
index 0000000..b9f072d
--- /dev/null
+++ b/git/middleware/repository.go
@@ -0,0 +1,118 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type Repository interface {
+	Remotes() Remotes
+	Walk() (RevWalk, error)
+	Head() (Reference, error)
+	LookupCommit(oid *git.Oid) (*git.Commit, error)
+	LookupCommitV2(oid *git.Oid) (Commit, error)
+	DefaultSignature() (*git.Signature, error)
+	LookupTree(id *git.Oid) (*git.Tree, error)
+	Index() (Index, error)
+	CreateCommit(s string, signature *git.Signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error)
+	DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error)
+	CreateBranch(string, *git.Commit, bool) (*git.Branch, error)
+	LookupBranch(branchName string, branchType git.BranchType) (Branch, error)
+	CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error
+	SetHead(name string) error
+	GetGitRepository() *git.Repository
+	NewBranchIterator(branchType git.BranchType) (BranchIterator, error)
+}
+
+type repository struct {
+	repo *git.Repository
+}
+
+func (r repository) NewBranchIterator(branchType git.BranchType) (BranchIterator, error) {
+	itr, err := r.repo.NewBranchIterator(branchType)
+	if err != nil {
+		return nil, err
+	}
+
+	return NewBranchIterator(itr), nil
+}
+
+func (r repository) SetHead(name string) error {
+	return r.repo.SetHead(name)
+}
+
+func (r repository) CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error {
+	return r.repo.CheckoutTree(tree, c)
+}
+
+func (r repository) Remotes() Remotes {
+	return NewRemotes(r.repo.Remotes)
+}
+
+func (r repository) CreateCommit(s string, signature *git.Signature, signature2 *git.Signature,
+	message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error) {
+	return r.repo.CreateCommit(s, signature, signature2, message, tree, parents...)
+}
+
+func (r repository) CreateBranch(branchName string, commit *git.Commit, force bool) (*git.Branch, error) {
+	return r.repo.CreateBranch(branchName, commit, force)
+}
+
+func (r repository) Head() (Reference, error) {
+	head, err := r.repo.Head()
+	if err != nil {
+		return nil, err
+	}
+	return NewReference(head), nil
+}
+
+func (r repository) Index() (Index, error) {
+	idx, err := r.repo.Index()
+	if err != nil {
+		return idx, err
+	}
+	return NewIndex(idx), nil
+}
+
+func (r repository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
+	return r.repo.LookupCommit(oid)
+}
+
+func (r repository) LookupCommitV2(oid *git.Oid) (Commit, error) {
+	gitCommit, err := r.repo.LookupCommit(oid)
+	if err != nil {
+		return nil, err
+	}
+	return NewCommit(gitCommit), nil
+}
+
+func (r repository) LookupBranch(branchName string, branchType git.BranchType) (Branch, error) {
+	gitBranch, err := r.repo.LookupBranch(branchName, branchType)
+	if err != nil {
+		return nil, err
+	}
+	return NewBranch(gitBranch), nil
+}
+
+func (r repository) LookupTree(id *git.Oid) (*git.Tree, error) {
+	return r.repo.LookupTree(id)
+}
+
+func (r repository) Walk() (RevWalk, error) {
+	walk, err := r.repo.Walk()
+
+	return NewRevWalk(walk), err
+}
+
+func (r repository) DefaultSignature() (*git.Signature, error) {
+	return r.repo.DefaultSignature()
+}
+
+func (r repository) DiffTreeToTree(tree *git.Tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error) {
+	return r.repo.DiffTreeToTree(tree, tree2, options)
+}
+
+func (r repository) GetGitRepository() *git.Repository {
+	return r.repo
+}
+
+func NewRepository(repo *git.Repository) Repository {
+	return repository{repo: repo}
+}
diff --git a/git/middleware/walk.go b/git/middleware/walk.go
new file mode 100644
index 0000000..fcb76d4
--- /dev/null
+++ b/git/middleware/walk.go
@@ -0,0 +1,29 @@
+package middleware
+
+import git "github.com/libgit2/git2go/v31"
+
+type RevWalk interface {
+	Iterate(iterator git.RevWalkIterator) error
+	PushHead() error
+	Push(id *git.Oid) error
+}
+
+type revWalk struct {
+	walk *git.RevWalk
+}
+
+func (w *revWalk) Push(id *git.Oid) error {
+	return w.walk.Push(id)
+}
+
+func (w *revWalk) PushHead() error {
+	return w.walk.PushHead()
+}
+
+func (w *revWalk) Iterate(iterator git.RevWalkIterator) error {
+	return w.walk.Iterate(iterator)
+}
+
+func NewRevWalk(walk *git.RevWalk) RevWalk {
+	return &revWalk{walk: walk}
+}
diff --git a/git/remote/git_remote_add.go b/git/remote/git_remote_add.go
new file mode 100644
index 0000000..76906da
--- /dev/null
+++ b/git/remote/git_remote_add.go
@@ -0,0 +1,44 @@
+package remote
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Add interface {
+	NewRemote() error
+}
+
+type addRemote struct {
+	repo             middleware.Repository
+	remoteName       string
+	remoteURL        string
+	remoteValidation Validation
+}
+
+// NewRemote adds a new remote to the target git repo
+func (a addRemote) NewRemote() error {
+	if validationErr := a.remoteValidation.ValidateRemoteFields(a.remoteName, a.remoteURL); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
+	}
+
+	remote, err := a.repo.Remotes().Create(a.remoteName, a.remoteURL)
+	if err != nil {
+		logger.Log("Remote addition Failed -> "+err.Error(), global.StatusError)
+		return err
+	}
+
+	logger.Log(fmt.Sprintf("New remote %s added to the repo", remote.Name()), global.StatusInfo)
+	return nil
+}
+
+func NewAddRemote(repo middleware.Repository, remoteName string, remoteURL string, remoteValidation Validation) Add {
+	return addRemote{
+		repo:             repo,
+		remoteName:       remoteName,
+		remoteURL:        remoteURL,
+		remoteValidation: remoteValidation,
+	}
+}
diff --git a/git/remote/git_remote_add_test.go b/git/remote/git_remote_add_test.go
new file mode 100644
index 0000000..dbdd2ec
--- /dev/null
+++ b/git/remote/git_remote_add_test.go
@@ -0,0 +1,86 @@
+package remote
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteAddTestSuite struct {
+	suite.Suite
+	mockController       *gomock.Controller
+	repo                 middleware.Repository
+	remotes              middleware.Remotes
+	mockRepo             *mocks.MockRepository
+	mockRemotes          *remoteMocks.MockRemotes
+	mockRemoteValidation *remoteMocks.MockValidation
+	remoteName           string
+	remoteUrl            string
+	addRemote            Add
+	remoteValidation     Validation
+}
+
+func TestRemoteAddTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteAddTestSuite))
+}
+
+func (suite *RemoteAddTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = middleware.NewRepository(r)
+	suite.remotes = middleware.NewRemotes(r.Remotes)
+	suite.remoteName = "new_origin"
+	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.addRemote = NewAddRemote(suite.mockRepo, suite.remoteName, suite.remoteUrl, suite.mockRemoteValidation)
+}
+
+func (suite *RemoteAddTestSuite) TearDownSuite() {
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+
+	err := NewDeleteRemote(suite.repo, suite.remoteName, suite.remoteValidation).DeleteRemote()
+	if err != nil {
+		logger.Log(err.Error(), global.StatusWarning)
+		return
+	}
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenNewRemoteIsAdded_ShouldReturnNil() {
+	suite.addRemote = NewAddRemote(suite.repo, suite.remoteName, suite.remoteUrl, suite.remoteValidation)
+
+	err := suite.addRemote.NewRemote()
+
+	suite.Nil(err)
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenValidationFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(errors.New("VALIDATION_ERROR"))
+
+	err := suite.addRemote.NewRemote()
+
+	suite.NotNil(err)
+}
+
+func (suite *RemoteAddTestSuite) TestAddNewRemote_WhenRemoteCreationFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Create(suite.remoteName, suite.remoteUrl).Return(&git2go.Remote{}, errors.New("REMOTE_ERROR"))
+
+	err := suite.addRemote.NewRemote()
+
+	suite.NotNil(err)
+}
diff --git a/git/remote/git_remote_delete.go b/git/remote/git_remote_delete.go
new file mode 100644
index 0000000..8067229
--- /dev/null
+++ b/git/remote/git_remote_delete.go
@@ -0,0 +1,52 @@
+package remote
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Delete interface {
+	DeleteRemote() error
+}
+
+type deleteRemote struct {
+	repo             middleware.Repository
+	remoteName       string
+	remoteValidation Validation
+}
+
+// DeleteRemote deletes the remote based on the specified remoteName
+func (d deleteRemote) DeleteRemote() error {
+	validationError := d.remoteValidation.ValidateRemoteFields(d.remoteName)
+	if validationError != nil {
+		return validationError
+	}
+
+	err := d.deleteSelectedRemote(d.remoteName)
+	if err != nil {
+		logger.Log(fmt.Sprintf("Remote => %s cannot be found in the repo", d.remoteName), global.StatusError)
+		return err
+	}
+
+	return nil
+}
+
+func (d *deleteRemote) deleteSelectedRemote(remoteName string) error {
+	err := d.repo.Remotes().Delete(remoteName)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+
+	logger.Log(fmt.Sprintf("The remote => %s deleted from repo", d.remoteName), global.StatusInfo)
+	return nil
+}
+
+func NewDeleteRemote(repo middleware.Repository, remoteName string, remoteValidation Validation) Delete {
+	return deleteRemote{
+		repo:             repo,
+		remoteName:       remoteName,
+		remoteValidation: remoteValidation,
+	}
+}
diff --git a/git/remote/git_remote_delete_test.go b/git/remote/git_remote_delete_test.go
new file mode 100644
index 0000000..4787ce3
--- /dev/null
+++ b/git/remote/git_remote_delete_test.go
@@ -0,0 +1,87 @@
+package remote
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteDeleteTestSuite struct {
+	suite.Suite
+	repo                 middleware.Repository
+	remoteName           string
+	deleteRemote         Delete
+	remoteValidation     Validation
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemotes          *remoteMocks.MockRemotes
+}
+
+func TestRemoteDeleteTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteDeleteTestSuite))
+}
+
+func (suite *RemoteDeleteTestSuite) SetupSuite() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = middleware.NewRepository(r)
+	suite.remoteName = "new_origin"
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+
+	_ = NewAddRemote(suite.repo, suite.remoteName, "remote://some_url", suite.remoteValidation).NewRemote()
+}
+
+func (suite *RemoteDeleteTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+	suite.repo = middleware.NewRepository(r)
+	suite.remoteName = "new_origin"
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
+	suite.deleteRemote = NewDeleteRemote(suite.mockRepo, suite.remoteName, suite.mockRemoteValidation)
+}
+
+func (suite *RemoteDeleteTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenNewRemoteIsDeleted_ShouldReturnNoError() {
+	suite.deleteRemote = NewDeleteRemote(suite.repo, suite.remoteName, suite.remoteValidation)
+	err := suite.deleteRemote.DeleteRemote()
+
+	suite.Nil(err)
+}
+
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteValidationFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName).Return(errors.New("VALIDATION_ERROR"))
+
+	err := suite.deleteRemote.DeleteRemote()
+
+	suite.NotNil(err)
+}
+
+func (suite *RemoteDeleteTestSuite) TestDeleteNewRemote_WhenRemoteDeletionFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Delete(suite.remoteName).Return(errors.New("DELETION_FAILS"))
+
+	err := suite.deleteRemote.DeleteRemote()
+
+	suite.NotNil(err)
+}
diff --git a/git/remote/git_remote_edit.go b/git/remote/git_remote_edit.go
new file mode 100644
index 0000000..874dd14
--- /dev/null
+++ b/git/remote/git_remote_edit.go
@@ -0,0 +1,80 @@
+package remote
+
+import (
+	"errors"
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Edit interface {
+	EditRemote() error
+}
+
+type editRemote struct {
+	repo             middleware.Repository
+	remoteName       string
+	remoteURL        string
+	remoteValidation Validation
+	remoteList       List
+}
+
+func (e editRemote) EditRemote() error {
+	repo := e.repo
+
+	validationErr := e.remoteValidation.ValidateRemoteFields(e.remoteName, e.remoteURL)
+	if validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return validationErr
+	}
+
+	_, listErr := repo.Remotes().List()
+	if listErr != nil {
+		logger.Log(listErr.Error(), global.StatusError)
+		return listErr
+	}
+
+	if remoteAvailabilityErr := e.isRemotePresentInRepo(); remoteAvailabilityErr != nil {
+		logger.Log(remoteAvailabilityErr.Error(), global.StatusError)
+		return remoteAvailabilityErr
+	}
+
+	err := repo.Remotes().SetUrl(e.remoteName, e.remoteURL)
+	if err != nil {
+		logger.Log(err.Error(), global.StatusError)
+		return err
+	}
+
+	logger.Log("Remote data has been updated successfully", global.StatusInfo)
+	return nil
+}
+
+func (e editRemote) isRemotePresentInRepo() error {
+	var err error
+	remoteList := e.remoteList.GetAllRemotes()
+
+	if remoteList == nil {
+		err = errors.New("no remotes are present in the repo")
+		return err
+	}
+
+	for _, remote := range remoteList {
+		if remote.RemoteName == e.remoteName {
+			logger.Log(fmt.Sprintf("Remote - %s is available in the repo", e.remoteName), global.StatusInfo)
+			return nil
+		}
+	}
+
+	err = errors.New(fmt.Sprintf("remote %s is not available in the repo", e.remoteName))
+	return err
+}
+
+func NewEditRemote(repo middleware.Repository, remoteName string, remoteURL string, remoteValidation Validation, remoteList List) Edit {
+	return editRemote{
+		repo:             repo,
+		remoteName:       remoteName,
+		remoteURL:        remoteURL,
+		remoteValidation: remoteValidation,
+		remoteList:       remoteList,
+	}
+}
diff --git a/git/remote/git_remote_edit_test.go b/git/remote/git_remote_edit_test.go
new file mode 100644
index 0000000..af7e50a
--- /dev/null
+++ b/git/remote/git_remote_edit_test.go
@@ -0,0 +1,126 @@
+package remote
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteEditTestSuite struct {
+	suite.Suite
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemoteList       *remoteMocks.MockList
+	mockRemotes          *remoteMocks.MockRemotes
+	remoteName           string
+	remoteUrl            string
+	remoteValidation     Validation
+	remoteList           List
+	editRemote           Edit
+}
+
+func TestRemoteEditTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteEditTestSuite))
+}
+
+func (suite *RemoteEditTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
+	suite.mockRemoteList = remoteMocks.NewMockList(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+
+	suite.remoteName = "origin"
+	suite.remoteUrl = "https://github.com/neel1996/gitconvex-test.git"
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo, suite.remoteValidation)
+	suite.editRemote = NewEditRemote(
+		suite.mockRepo,
+		suite.remoteName,
+		suite.remoteUrl,
+		suite.mockRemoteValidation,
+		suite.mockRemoteList,
+	)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsEdited_ShouldReturnNil() {
+	suite.editRemote = NewEditRemote(suite.repo, suite.remoteName, suite.remoteUrl, suite.remoteValidation, suite.remoteList)
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.Nil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteValidationFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(errors.New("VALIDATION_ERR"))
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteListReturnsError_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return(nil, errors.New("LIST_ERROR"))
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsNotPresent_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return(nil)
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteIsNotPresentInRepo_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{{
+		RemoteName: "INVALID",
+	}})
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
+
+func (suite *RemoteEditTestSuite) TestEditRemote_WhenRemoteSetUrlFails_ShouldReturnError() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields(suite.remoteName, suite.remoteUrl).Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{{
+		RemoteName: suite.remoteName,
+		RemoteURL:  suite.remoteUrl,
+	}})
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().SetUrl(suite.remoteName, suite.remoteUrl).Return(errors.New("SET_URL_ERROR"))
+
+	wantErr := suite.editRemote.EditRemote()
+
+	suite.NotNil(wantErr)
+}
diff --git a/git/remote/git_remote_get_host.go b/git/remote/git_remote_get_host.go
new file mode 100644
index 0000000..e52b685
--- /dev/null
+++ b/git/remote/git_remote_get_host.go
@@ -0,0 +1,27 @@
+package remote
+
+import "strings"
+
+type Host interface {
+	GetRemoteHostForUrl() string
+}
+
+type host struct {
+	remoteUrl string
+}
+
+func (h host) GetRemoteHostForUrl() string {
+	var remoteHostNames = []string{"github", "gitlab", "bitbucket", "azure", "codecommit"}
+
+	for _, hostName := range remoteHostNames {
+		if strings.Contains(h.remoteUrl, hostName) {
+			return hostName
+		}
+	}
+
+	return ""
+}
+
+func NewRemoteHost(remoteUrl string) Host {
+	return host{remoteUrl: remoteUrl}
+}
diff --git a/git/remote/git_remote_get_host_test.go b/git/remote/git_remote_get_host_test.go
new file mode 100644
index 0000000..1a08c8d
--- /dev/null
+++ b/git/remote/git_remote_get_host_test.go
@@ -0,0 +1,33 @@
+package remote
+
+import (
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type RemoteHostTestSuite struct {
+	suite.Suite
+	host Host
+}
+
+func TestRemoteHostTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteHostTestSuite))
+}
+
+func (suite *RemoteHostTestSuite) SetupTest() {
+	suite.host = NewRemoteHost("https://github.com/test/test.git")
+}
+
+func (suite *RemoteHostTestSuite) TestGetRemoteHost_WhenRemoteUrlIsPassed_ShouldReturnHostName() {
+	expectedHost := "github"
+	remoteHost := suite.host.GetRemoteHostForUrl()
+
+	suite.Equal(expectedHost, remoteHost)
+}
+
+func (suite *RemoteHostTestSuite) TestGetRemoteHost_WhenRemoteUrlContainsUnknownHost_ShouldReturnEmptyString() {
+	suite.host = NewRemoteHost("https://orca.com/test/test.git")
+	remoteHost := suite.host.GetRemoteHostForUrl()
+
+	suite.Equal("", remoteHost)
+}
diff --git a/git/remote/git_remote_list.go b/git/remote/git_remote_list.go
new file mode 100644
index 0000000..979b61a
--- /dev/null
+++ b/git/remote/git_remote_list.go
@@ -0,0 +1,60 @@
+package remote
+
+import (
+	"fmt"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+type List interface {
+	GetAllRemotes() []*model.RemoteDetails
+}
+
+type listRemotes struct {
+	repo             middleware.Repository
+	remoteValidation Validation
+}
+
+func (l listRemotes) GetAllRemotes() []*model.RemoteDetails {
+	var remoteList []*model.RemoteDetails
+	repo := l.repo
+
+	if validationErr := l.remoteValidation.ValidateRemoteFields(); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return nil
+	}
+
+	list, listErr := repo.Remotes().List()
+	if listErr != nil {
+		logger.Log(listErr.Error(), global.StatusError)
+		return nil
+	}
+
+	for _, remoteEntry := range list {
+		remote, remoteErr := repo.Remotes().Lookup(remoteEntry)
+		if remoteErr != nil {
+			logger.Log(remoteErr.Error(), global.StatusError)
+			continue
+		}
+
+		data := model.RemoteDetails{
+			RemoteName: remote.Name(),
+			RemoteURL:  remote.Url(),
+		}
+		remoteList = append(remoteList, &data)
+	}
+
+	if len(remoteList) == 0 {
+		logger.Log(fmt.Sprintf("No remotes available for the repo"), global.StatusWarning)
+		return nil
+	}
+
+	logger.Log(fmt.Sprintf("Remote data fetched => %+v", remoteList), global.StatusInfo)
+
+	return remoteList
+}
+
+func NewRemoteList(repo middleware.Repository, remoteValidation Validation) List {
+	return listRemotes{repo: repo, remoteValidation: remoteValidation}
+}
diff --git a/git/remote/git_remote_list_test.go b/git/remote/git_remote_list_test.go
new file mode 100644
index 0000000..b7175ee
--- /dev/null
+++ b/git/remote/git_remote_list_test.go
@@ -0,0 +1,89 @@
+package remote
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type ListRemoteTestSuite struct {
+	suite.Suite
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemotes          *remoteMocks.MockRemotes
+	listRemote           List
+	remoteValidation     Validation
+}
+
+func (suite *ListRemoteTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.repo = middleware.NewRepository(r)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
+	suite.listRemote = NewRemoteList(suite.mockRepo, suite.mockRemoteValidation)
+}
+
+func TestListRemoteTestSuite(t *testing.T) {
+	suite.Run(t, new(ListRemoteTestSuite))
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoIsValid_ShouldReturnAllRemotes() {
+	suite.listRemote = NewRemoteList(suite.repo, suite.remoteValidation)
+
+	expectedRemotes := []*model.RemoteDetails{{
+		RemoteName: "origin",
+		RemoteURL:  "https://github.com/neel1996/gitconvex-test.git",
+	}}
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Equal(len(expectedRemotes), len(remoteList))
+	suite.Equal(expectedRemotes[0].RemoteName, remoteList[0].RemoteName)
+	suite.Equal(expectedRemotes[0].RemoteURL, remoteList[0].RemoteURL)
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRemoteValidationFails_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Nil(remoteList)
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRepoHasNoRemotes_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().List().Return([]string{}, errors.New("LIST_ERROR"))
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Nil(remoteList)
+}
+
+func (suite *ListRemoteTestSuite) TestGetAllRemotes_WhenRemoteLookupFails_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes).MaxTimes(2)
+	suite.mockRemotes.EXPECT().List().Return([]string{"REMOTE"}, nil)
+	suite.mockRemotes.EXPECT().Lookup("REMOTE").Return(&git2go.Remote{}, errors.New("LOOKUP_ERROR"))
+
+	remoteList := suite.listRemote.GetAllRemotes()
+
+	suite.Nil(remoteList)
+}
diff --git a/git/remote/git_remote_remote_name.go b/git/remote/git_remote_remote_name.go
new file mode 100644
index 0000000..72b14d6
--- /dev/null
+++ b/git/remote/git_remote_remote_name.go
@@ -0,0 +1,48 @@
+package remote
+
+import (
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type Name interface {
+	GetRemoteNameWithUrl() string
+}
+
+type remoteName struct {
+	repo             middleware.Repository
+	remoteUrl        string
+	remoteValidation Validation
+	remoteList       List
+}
+
+func (r remoteName) GetRemoteNameWithUrl() string {
+	if validationErr := r.remoteValidation.ValidateRemoteFields(); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return ""
+	}
+
+	remoteList := r.remoteList.GetAllRemotes()
+	if remoteList == nil {
+		logger.Log("repo has no remotes", global.StatusError)
+		return ""
+	}
+
+	for _, remote := range remoteList {
+		if r.remoteUrl == remote.RemoteURL {
+			logger.Log("Matching remote found for the URL", global.StatusInfo)
+			return remote.RemoteName
+		}
+	}
+
+	return ""
+}
+
+func NewGetRemoteName(repo middleware.Repository, remoteUrl string, remoteValidation Validation, remoteList List) Name {
+	return remoteName{
+		repo:             repo,
+		remoteUrl:        remoteUrl,
+		remoteValidation: remoteValidation,
+		remoteList:       remoteList,
+	}
+}
diff --git a/git/remote/git_remote_remote_name_test.go b/git/remote/git_remote_remote_name_test.go
new file mode 100644
index 0000000..6940ec7
--- /dev/null
+++ b/git/remote/git_remote_remote_name_test.go
@@ -0,0 +1,100 @@
+package remote
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type GetRemoteNameTestSuite struct {
+	suite.Suite
+	getRemoteName        Name
+	repo                 middleware.Repository
+	remoteValidation     Validation
+	remoteList           List
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteValidation *remoteMocks.MockValidation
+	mockRemoteList       *remoteMocks.MockList
+	noHeadRepo           *git2go.Repository
+}
+
+func (suite *GetRemoteNameTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo, suite.remoteValidation)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.mockRemoteList = remoteMocks.NewMockList(suite.mockController)
+	suite.getRemoteName = NewGetRemoteName(
+		suite.mockRepo,
+		"https://github.com/neel1996/gitconvex-test.git",
+		suite.mockRemoteValidation,
+		suite.mockRemoteList,
+	)
+}
+
+func TestGetRemoteNameTestSuite(t *testing.T) {
+	suite.Run(t, new(GetRemoteNameTestSuite))
+}
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnRemoteName_WhenRemoteUrlIsValid() {
+	suite.getRemoteName = NewGetRemoteName(
+		suite.repo,
+		"https://github.com/neel1996/gitconvex-test.git",
+		suite.remoteValidation,
+		suite.remoteList,
+	)
+
+	expectedRemote := "origin"
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenValidationFails() {
+	expectedRemote := ""
+
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERROR"))
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRepoHasNoRemotes() {
+	expectedRemote := ""
+
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return(nil)
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}
+
+func (suite *GetRemoteNameTestSuite) TestGetRemoteName_ShouldReturnEmptyString_WhenRemoteURLIsNotPresentInRepo() {
+	expectedRemote := ""
+
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{})
+
+	actualRemote := suite.getRemoteName.GetRemoteNameWithUrl()
+
+	suite.Equal(expectedRemote, actualRemote)
+}
diff --git a/git/remote/git_remote_url_data.go b/git/remote/git_remote_url_data.go
new file mode 100644
index 0000000..53faf8b
--- /dev/null
+++ b/git/remote/git_remote_url_data.go
@@ -0,0 +1,50 @@
+package remote
+
+import (
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/global"
+)
+
+type ListRemoteUrl interface {
+	GetAllRemoteUrl() []*string
+}
+
+type listRemoteUrl struct {
+	repo             middleware.Repository
+	remoteValidation Validation
+	remoteList       List
+}
+
+func (u listRemoteUrl) GetAllRemoteUrl() []*string {
+	var remoteURL []*string
+
+	if validationErr := u.remoteValidation.ValidateRemoteFields(); validationErr != nil {
+		logger.Log(validationErr.Error(), global.StatusError)
+		return nil
+	}
+
+	remoteList := u.remoteList.GetAllRemotes()
+	if remoteList == nil {
+		logger.Log("repo has no remotes", global.StatusError)
+		return nil
+	}
+
+	for _, remote := range remoteList {
+		remoteURL = append(remoteURL, &remote.RemoteURL)
+	}
+
+	if len(remoteURL) == 0 {
+		logger.Log("No remotes present in the repo", global.StatusError)
+		return nil
+	}
+
+	return remoteURL
+}
+
+func NewRemoteUrlData(repo middleware.Repository, remoteValidation Validation, remoteList List) ListRemoteUrl {
+	return listRemoteUrl{
+		repo:             repo,
+		remoteValidation: remoteValidation,
+		remoteList:       remoteList,
+	}
+}
diff --git a/git/remote/git_remote_url_data_test.go b/git/remote/git_remote_url_data_test.go
new file mode 100644
index 0000000..aac5746
--- /dev/null
+++ b/git/remote/git_remote_url_data_test.go
@@ -0,0 +1,83 @@
+package remote
+
+import (
+	"errors"
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
+	"github.com/neel1996/gitconvex/graph/model"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteUrlDataTestSuite struct {
+	suite.Suite
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemoteList       *remoteMocks.MockList
+	mockRemoteValidation *remoteMocks.MockValidation
+	remoteValidation     Validation
+	remoteList           List
+	listRemoteUrl        ListRemoteUrl
+}
+
+func TestRemoteUrlDataTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteUrlDataTestSuite))
+}
+
+func (suite *RemoteUrlDataTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.repo = middleware.NewRepository(r)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.remoteList = NewRemoteList(suite.repo, suite.remoteValidation)
+	suite.remoteValidation = NewRemoteValidation(suite.repo)
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.mockRemoteValidation = remoteMocks.NewMockValidation(suite.mockController)
+	suite.mockRemoteList = remoteMocks.NewMockList(suite.mockController)
+	suite.listRemoteUrl = NewRemoteUrlData(suite.mockRepo, suite.mockRemoteValidation, suite.mockRemoteList)
+}
+
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesArePresent_ShouldReturnRemoteUrlList() {
+	suite.listRemoteUrl = NewRemoteUrlData(suite.repo, suite.remoteValidation, suite.remoteList)
+
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.NotZero(len(urlList))
+	suite.Equal("https://github.com/neel1996/gitconvex-test.git", *urlList[0])
+}
+
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemoteValidationFails_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(errors.New("VALIDATION_ERR"))
+
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.Nil(urlList)
+}
+
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRepoHasNoRemotes_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return(nil)
+
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.Nil(urlList)
+}
+
+func (suite *RemoteUrlDataTestSuite) TestGetAllRemoteUrl_WhenRemotesAreNil_ShouldReturnNil() {
+	suite.mockRemoteValidation.EXPECT().ValidateRemoteFields().Return(nil)
+	suite.mockRemoteList.EXPECT().GetAllRemotes().Return([]*model.RemoteDetails{})
+
+	urlList := suite.listRemoteUrl.GetAllRemoteUrl()
+
+	suite.Nil(urlList)
+}
diff --git a/git/remote/mocks/mock_git_remote_list.go b/git/remote/mocks/mock_git_remote_list.go
new file mode 100644
index 0000000..878dc3d
--- /dev/null
+++ b/git/remote/mocks/mock_git_remote_list.go
@@ -0,0 +1,49 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/remote/git_remote_list.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	model "github.com/neel1996/gitconvex/graph/model"
+)
+
+// MockList is a mock of List interface.
+type MockList struct {
+	ctrl     *gomock.Controller
+	recorder *MockListMockRecorder
+}
+
+// MockListMockRecorder is the mock recorder for MockList.
+type MockListMockRecorder struct {
+	mock *MockList
+}
+
+// NewMockList creates a new mock instance.
+func NewMockList(ctrl *gomock.Controller) *MockList {
+	mock := &MockList{ctrl: ctrl}
+	mock.recorder = &MockListMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockList) EXPECT() *MockListMockRecorder {
+	return m.recorder
+}
+
+// GetAllRemotes mocks base method.
+func (m *MockList) GetAllRemotes() []*model.RemoteDetails {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetAllRemotes")
+	ret0, _ := ret[0].([]*model.RemoteDetails)
+	return ret0
+}
+
+// GetAllRemotes indicates an expected call of GetAllRemotes.
+func (mr *MockListMockRecorder) GetAllRemotes() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllRemotes", reflect.TypeOf((*MockList)(nil).GetAllRemotes))
+}
diff --git a/git/remote/mocks/mock_remote_validation.go b/git/remote/mocks/mock_remote_validation.go
new file mode 100644
index 0000000..d5042c4
--- /dev/null
+++ b/git/remote/mocks/mock_remote_validation.go
@@ -0,0 +1,52 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/remote/remote_validation.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockValidation is a mock of Validation interface.
+type MockValidation struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidationMockRecorder
+}
+
+// MockValidationMockRecorder is the mock recorder for MockValidation.
+type MockValidationMockRecorder struct {
+	mock *MockValidation
+}
+
+// NewMockValidation creates a new mock instance.
+func NewMockValidation(ctrl *gomock.Controller) *MockValidation {
+	mock := &MockValidation{ctrl: ctrl}
+	mock.recorder = &MockValidationMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidation) EXPECT() *MockValidationMockRecorder {
+	return m.recorder
+}
+
+// ValidateRemoteFields mocks base method.
+func (m *MockValidation) ValidateRemoteFields(remoteFields ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{}
+	for _, a := range remoteFields {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateRemoteFields", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ValidateRemoteFields indicates an expected call of ValidateRemoteFields.
+func (mr *MockValidationMockRecorder) ValidateRemoteFields(remoteFields ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRemoteFields", reflect.TypeOf((*MockValidation)(nil).ValidateRemoteFields), remoteFields...)
+}
diff --git a/git/remote/mocks/mock_remotes.go b/git/remote/mocks/mock_remotes.go
new file mode 100644
index 0000000..292cf21
--- /dev/null
+++ b/git/remote/mocks/mock_remotes.go
@@ -0,0 +1,122 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/remotes.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockRemotes is a mock of Remotes interface.
+type MockRemotes struct {
+	ctrl     *gomock.Controller
+	recorder *MockRemotesMockRecorder
+}
+
+// MockRemotesMockRecorder is the mock recorder for MockRemotes.
+type MockRemotesMockRecorder struct {
+	mock *MockRemotes
+}
+
+// NewMockRemotes creates a new mock instance.
+func NewMockRemotes(ctrl *gomock.Controller) *MockRemotes {
+	mock := &MockRemotes{ctrl: ctrl}
+	mock.recorder = &MockRemotesMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRemotes) EXPECT() *MockRemotesMockRecorder {
+	return m.recorder
+}
+
+// Create mocks base method.
+func (m *MockRemotes) Create(arg0, arg1 string) (*git.Remote, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Create", arg0, arg1)
+	ret0, _ := ret[0].(*git.Remote)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Create indicates an expected call of Create.
+func (mr *MockRemotesMockRecorder) Create(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockRemotes)(nil).Create), arg0, arg1)
+}
+
+// Delete mocks base method.
+func (m *MockRemotes) Delete(arg0 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Delete", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Delete indicates an expected call of Delete.
+func (mr *MockRemotesMockRecorder) Delete(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRemotes)(nil).Delete), arg0)
+}
+
+// Get mocks base method.
+func (m *MockRemotes) Get() git.RemoteCollection {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Get")
+	ret0, _ := ret[0].(git.RemoteCollection)
+	return ret0
+}
+
+// Get indicates an expected call of Get.
+func (mr *MockRemotesMockRecorder) Get() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockRemotes)(nil).Get))
+}
+
+// List mocks base method.
+func (m *MockRemotes) List() ([]string, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "List")
+	ret0, _ := ret[0].([]string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// List indicates an expected call of List.
+func (mr *MockRemotesMockRecorder) List() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockRemotes)(nil).List))
+}
+
+// Lookup mocks base method.
+func (m *MockRemotes) Lookup(arg0 string) (*git.Remote, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Lookup", arg0)
+	ret0, _ := ret[0].(*git.Remote)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Lookup indicates an expected call of Lookup.
+func (mr *MockRemotesMockRecorder) Lookup(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lookup", reflect.TypeOf((*MockRemotes)(nil).Lookup), arg0)
+}
+
+// SetUrl mocks base method.
+func (m *MockRemotes) SetUrl(arg0, arg1 string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetUrl", arg0, arg1)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SetUrl indicates an expected call of SetUrl.
+func (mr *MockRemotesMockRecorder) SetUrl(arg0, arg1 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUrl", reflect.TypeOf((*MockRemotes)(nil).SetUrl), arg0, arg1)
+}
diff --git a/git/remote/remote.go b/git/remote/remote.go
new file mode 100644
index 0000000..a476769
--- /dev/null
+++ b/git/remote/remote.go
@@ -0,0 +1,100 @@
+package remote
+
+import (
+	"errors"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/global"
+	"github.com/neel1996/gitconvex/graph/model"
+)
+
+var logger global.Logger
+
+type Remote interface {
+	GitAddRemote() (*model.RemoteMutationResult, error)
+	GitDeleteRemote() (*model.RemoteMutationResult, error)
+	GitEditRemote() (*model.RemoteMutationResult, error)
+	GitGetAllRemote() ([]*model.RemoteDetails, error)
+	GitGetRemoteHostName() (string, error)
+	GitRemoteName() (string, error)
+	GitGetAllRemoteUrl() ([]*string, error)
+}
+
+type Operation struct {
+	Add           Add
+	Delete        Delete
+	Edit          Edit
+	Host          Host
+	List          List
+	Name          Name
+	ListRemoteUrl ListRemoteUrl
+}
+
+func (r Operation) GitAddRemote() (*model.RemoteMutationResult, error) {
+	addRemoteErr := r.Add.NewRemote()
+
+	if addRemoteErr != nil {
+		return nil, errors.New(global.RemoteAddError)
+	}
+
+	return &model.RemoteMutationResult{Status: global.RemoteAddSuccess}, nil
+}
+
+func (r Operation) GitDeleteRemote() (*model.RemoteMutationResult, error) {
+	err := r.Delete.DeleteRemote()
+
+	if err != nil {
+		return nil, constants.RemoteDeleteError
+	}
+
+	return &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}, nil
+}
+
+func (r Operation) GitEditRemote() (*model.RemoteMutationResult, error) {
+	err := r.Edit.EditRemote()
+
+	if err != nil {
+		return nil, err
+	}
+
+	return &model.RemoteMutationResult{Status: global.RemoteEditSuccess}, nil
+}
+
+func (r Operation) GitGetRemoteHostName() (string, error) {
+	remoteHost := r.Host.GetRemoteHostForUrl()
+
+	if remoteHost == "" {
+		return "", errors.New("unable to find a matching host name")
+	}
+
+	return remoteHost, nil
+}
+
+func (r Operation) GitGetAllRemote() ([]*model.RemoteDetails, error) {
+	allRemotes := r.List.GetAllRemotes()
+
+	if allRemotes == nil {
+		return nil, errors.New("unable to fetch remotes from the repo")
+	}
+
+	return allRemotes, nil
+}
+
+func (r Operation) GitRemoteName() (string, error) {
+	remoteHost := r.Name.GetRemoteNameWithUrl()
+
+	if remoteHost == "" {
+		return "", errors.New("no matching remote found for the URL")
+	}
+
+	return remoteHost, nil
+}
+
+func (r Operation) GitGetAllRemoteUrl() ([]*string, error) {
+	remoteUrlList := r.ListRemoteUrl.GetAllRemoteUrl()
+
+	if remoteUrlList == nil {
+		return nil, errors.New("unable to fetch remote URLs from the repo")
+	}
+
+	return remoteUrlList, nil
+}
diff --git a/git/remote/remote_validation.go b/git/remote/remote_validation.go
new file mode 100644
index 0000000..539a924
--- /dev/null
+++ b/git/remote/remote_validation.go
@@ -0,0 +1,67 @@
+package remote
+
+import (
+	"errors"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+)
+
+type Validation interface {
+	ValidateRemoteFields(remoteFields ...string) error
+}
+
+type validation struct {
+	repo         middleware.Repository
+	remoteFields []string
+}
+
+func (v validation) ValidateRemoteFields(remoteFields ...string) error {
+	v.remoteFields = remoteFields
+	validateRepoErr := v.validateRepo()
+	if validateRepoErr != nil {
+		return validateRepoErr
+	}
+
+	validateRemotesErr := v.validateRemoteCollection()
+	if validateRemotesErr != nil {
+		return validateRemotesErr
+	}
+
+	fieldValidationErr := v.validateRemoteFields()
+	if fieldValidationErr != nil {
+		return fieldValidationErr
+	}
+
+	return nil
+}
+
+func (v validation) validateRemoteFields() error {
+	for _, field := range v.remoteFields {
+		if field == "" {
+			return errors.New("one or more remote fields are empty")
+		}
+	}
+	return nil
+}
+
+func (v validation) validateRepo() error {
+	if v.repo == nil {
+		return errors.New("repo is nil")
+	}
+
+	return nil
+}
+
+func (v validation) validateRemoteCollection() error {
+	if v.repo.Remotes().Get() == (git2go.RemoteCollection{}) {
+		return errors.New("remote collection is nil")
+	}
+
+	return nil
+}
+
+func NewRemoteValidation(repo middleware.Repository) Validation {
+	return validation{
+		repo: repo,
+	}
+}
diff --git a/git/remote/remote_validation_test.go b/git/remote/remote_validation_test.go
new file mode 100644
index 0000000..733cc16
--- /dev/null
+++ b/git/remote/remote_validation_test.go
@@ -0,0 +1,83 @@
+package remote
+
+import (
+	"fmt"
+	"github.com/golang/mock/gomock"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/git/middleware"
+	remoteMocks "github.com/neel1996/gitconvex/git/remote/mocks"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"os"
+	"testing"
+)
+
+type RemoteValidationTestSuite struct {
+	suite.Suite
+	repo                 middleware.Repository
+	mockController       *gomock.Controller
+	mockRepo             *mocks.MockRepository
+	mockRemotes          *remoteMocks.MockRemotes
+	remoteFields         []string
+	validateRemoteFields Validation
+}
+
+func TestRemoteValidationTestSuite(t *testing.T) {
+	suite.Run(t, new(RemoteValidationTestSuite))
+}
+
+func (suite *RemoteValidationTestSuite) SetupTest() {
+	r, err := git2go.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	suite.remoteFields = []string{"origin", "origin_1"}
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.repo = middleware.NewRepository(r)
+	suite.mockRemotes = remoteMocks.NewMockRemotes(suite.mockController)
+	suite.validateRemoteFields = NewRemoteValidation(suite.mockRepo)
+}
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenAllFieldsAreValid_ShouldReturnNil() {
+	suite.validateRemoteFields = NewRemoteValidation(suite.repo)
+
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields(suite.remoteFields[0], suite.remoteFields[1])
+
+	suite.Nil(wantErr)
+}
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRepoIsNil_ShouldReturnError() {
+	suite.validateRemoteFields = NewRemoteValidation(nil)
+
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
+	wantErrorText := "repo is nil"
+
+	suite.NotNil(wantErr)
+	suite.Equal(wantErrorText, wantErr.Error())
+}
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteCollectionIsNil_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Get().Return(git2go.RemoteCollection{})
+
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields()
+	wantErrorText := "remote collection is nil"
+
+	suite.NotNil(wantErr)
+	suite.Equal(wantErrorText, wantErr.Error())
+}
+
+func (suite *RemoteValidationTestSuite) TestValidateRemoteFields_WhenRemoteFieldsAreEmpty_ShouldReturnError() {
+	suite.mockRepo.EXPECT().Remotes().Return(suite.mockRemotes)
+	suite.mockRemotes.EXPECT().Get().DoAndReturn(func() git2go.RemoteCollection {
+		return suite.repo.Remotes().Get()
+	})
+
+	wantErr := suite.validateRemoteFields.ValidateRemoteFields("", "")
+	wantErrorText := "one or more remote fields are empty"
+
+	suite.NotNil(wantErr)
+	suite.Equal(wantErrorText, wantErr.Error())
+}
diff --git a/global/default_dir_const.go b/global/default_dir_const.go
new file mode 100644
index 0000000..90c6d37
--- /dev/null
+++ b/global/default_dir_const.go
@@ -0,0 +1,5 @@
+package global
+
+func GetDefaultDirectory() string {
+	return "GENERATED_ENV_STRING_GOES_HERE"
+}
diff --git a/global/errors.go b/global/errors.go
index 41cd8db..e19980a 100644
--- a/global/errors.go
+++ b/global/errors.go
@@ -5,8 +5,6 @@ const (
 	BranchCheckoutError  = "CHECKOUT_FAILED"
 	BranchDeleteError    = "BRANCH_DELETE_FAILED"
 	RemoteAddError       = "REMOTE_ADD_FAILED"
-	RemoteDeleteError    = "REMOTE_DELETE_FAILED"
-	RemoteEditError      = "REMOTE_EDIT_FAILED"
 	FetchFromRemoteError = "FETCH_ERROR"
 	PullFromRemoteError  = "PULL_ERROR"
 	StageItemError       = "ADD_ITEM_FAILED"
diff --git a/global/status_strings.go b/global/status_strings.go
index f1eb09a..aeee579 100644
--- a/global/status_strings.go
+++ b/global/status_strings.go
@@ -2,6 +2,7 @@ package global
 
 const (
 	BranchAddSuccess       = "BRANCH_CREATION_SUCCESS"
+	BranchCheckoutSuccess  = "BRANCH_CHECKOUT_SUCCESS"
 	BranchDeleteSuccess    = "BRANCH_DELETE_SUCCESS"
 	RemoteAddSuccess       = "REMOTE_ADD_SUCCESS"
 	RemoteDeleteSuccess    = "REMOTE_DELETE_SUCCESS"
diff --git a/go.mod b/go.mod
index da2f322..7f7b3b1 100644
--- a/go.mod
+++ b/go.mod
@@ -4,12 +4,13 @@ go 1.16
 
 require (
 	github.com/99designs/gqlgen v0.13.0
+	github.com/golang/mock v1.6.0
 	github.com/google/uuid v1.1.2
 	github.com/gorilla/mux v1.8.0
 	github.com/libgit2/git2go/v31 v31.4.10
 	github.com/rs/cors v1.7.0
 	github.com/sirupsen/logrus v1.8.1
-	github.com/stretchr/testify v1.4.0
+	github.com/stretchr/testify v1.7.0
 	github.com/vektah/gqlparser/v2 v2.1.0
 	golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c
 )
diff --git a/go.sum b/go.sum
index 23462a2..f402527 100644
--- a/go.sum
+++ b/go.sum
@@ -16,6 +16,8 @@ github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMN
 github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
 github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
 github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
 github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
@@ -61,40 +63,57 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
 github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
 github.com/vektah/gqlparser/v2 v2.1.0 h1:uiKJ+T5HMGGQM2kRKQ8Pxw8+Zq9qhhZhz/lieYvCMns=
 github.com/vektah/gqlparser/v2 v2.1.0/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c h1:9HhBz5L/UjnK9XLtiZhYAdue5BVKep3PMmS2LuPDt8k=
 golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201204225414-ed752295db88 h1:KmZPnMocC93w341XZp26yTJg8Za7lhb2KhkYmixoeso=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
 sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
diff --git a/graph/generated/generated.go b/graph/generated/generated.go
index cba9747..d049432 100644
--- a/graph/generated/generated.go
+++ b/graph/generated/generated.go
@@ -97,7 +97,7 @@ type ComplexityRoot struct {
 		AddRemote           func(childComplexity int, repoID string, remoteName string, remoteURL string) int
 		AddRepo             func(childComplexity int, repoName string, repoPath string, cloneSwitch bool, repoURL *string, initSwitch bool, authOption string, sshKeyPath *string, userName *string, password *string) int
 		CheckoutBranch      func(childComplexity int, repoID string, branchName string) int
-		CommitChanges       func(childComplexity int, repoID string, commitMessage string) int
+		CommitChanges       func(childComplexity int, repoID string, commitMessage []*string) int
 		DeleteBranch        func(childComplexity int, repoID string, branchName string, forceFlag bool) int
 		DeleteRemote        func(childComplexity int, repoID string, remoteName string) int
 		DeleteRepo          func(childComplexity int, repoID string) int
@@ -206,7 +206,7 @@ type MutationResolver interface {
 	RemoveStagedItem(ctx context.Context, repoID string, item string) (string, error)
 	RemoveAllStagedItem(ctx context.Context, repoID string) (string, error)
 	StageAllItems(ctx context.Context, repoID string) (string, error)
-	CommitChanges(ctx context.Context, repoID string, commitMessage string) (string, error)
+	CommitChanges(ctx context.Context, repoID string, commitMessage []*string) (string, error)
 	PushToRemote(ctx context.Context, repoID string, remoteHost string, branch string) (string, error)
 	SettingsEditPort(ctx context.Context, newPort string) (string, error)
 	UpdateRepoDataFile(ctx context.Context, newDbFile string) (string, error)
@@ -482,7 +482,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
 			return 0, false
 		}
 
-		return e.complexity.Mutation.CommitChanges(childComplexity, args["repoId"].(string), args["commitMessage"].(string)), true
+		return e.complexity.Mutation.CommitChanges(childComplexity, args["repoId"].(string), args["commitMessage"].([]*string)), true
 
 	case "Mutation.deleteBranch":
 		if e.complexity.Mutation.DeleteBranch == nil {
@@ -1108,7 +1108,7 @@ type GitRepoStatusResults {
     "Remote host name based on the remote URL (E.g: https://github.com/github/repo.git -> Github)"
     gitRemoteHost: String
     "Total number of commits tracked by the current branch"
-    gitTotalCommits: Float
+    gitTotalCommits: Int
     "The latest commit (HEAD commit)"
     gitLatestCommit: String
     "Total number of files tracked by git repo"
@@ -1131,7 +1131,7 @@ Returns the total number of commits in the repo and the array of 10 commit log e
 """
 type GitCommitLogResults {
     "Total number of commits tracked by the branch"
-    totalCommits: Float
+    totalCommits: Int
     "Array of commit log entries ` + "`" + `gitCommits` + "`" + `"
     commits: [gitCommits]
 }
@@ -1501,7 +1501,7 @@ type Mutation {
         "The UUID of the repo. It will be available in the JSON data file"
         repoId: String!,
         "The message for the commit"
-        commitMessage: String!
+        commitMessage: [String]!
     ): String!
 
     "Pushes the commits to the remote"
@@ -1756,10 +1756,10 @@ func (ec *executionContext) field_Mutation_commitChanges_args(ctx context.Contex
 		}
 	}
 	args["repoId"] = arg0
-	var arg1 string
+	var arg1 []*string
 	if tmp, ok := rawArgs["commitMessage"]; ok {
 		ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("commitMessage"))
-		arg1, err = ec.unmarshalNString2string(ctx, tmp)
+		arg1, err = ec.unmarshalNString2ᚕᚖstring(ctx, tmp)
 		if err != nil {
 			return nil, err
 		}
@@ -2831,9 +2831,9 @@ func (ec *executionContext) _GitCommitLogResults_totalCommits(ctx context.Contex
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(*float64)
+	res := resTmp.(*int)
 	fc.Result = res
-	return ec.marshalOFloat2ᚖfloat64(ctx, field.Selections, res)
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _GitCommitLogResults_commits(ctx context.Context, field graphql.CollectedField, obj *model.GitCommitLogResults) (ret graphql.Marshaler) {
@@ -2865,7 +2865,7 @@ func (ec *executionContext) _GitCommitLogResults_commits(ctx context.Context, fi
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _GitFolderContentResults_trackedFiles(ctx context.Context, field graphql.CollectedField, obj *model.GitFolderContentResults) (ret graphql.Marshaler) {
@@ -3157,9 +3157,9 @@ func (ec *executionContext) _GitRepoStatusResults_gitTotalCommits(ctx context.Co
 	if resTmp == nil {
 		return graphql.Null
 	}
-	res := resTmp.(*float64)
+	res := resTmp.(*int)
 	fc.Result = res
-	return ec.marshalOFloat2ᚖfloat64(ctx, field.Selections, res)
+	return ec.marshalOInt2ᚖint(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _GitRepoStatusResults_gitLatestCommit(ctx context.Context, field graphql.CollectedField, obj *model.GitRepoStatusResults) (ret graphql.Marshaler) {
@@ -3335,7 +3335,7 @@ func (ec *executionContext) _Mutation_addRepo(ctx context.Context, field graphql
 	}
 	res := resTmp.(*model.AddRepoParams)
 	fc.Result = res
-	return ec.marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐAddRepoParams(ctx, field.Selections, res)
+	return ec.marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐAddRepoParams(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_addBranch(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3461,7 +3461,7 @@ func (ec *executionContext) _Mutation_deleteBranch(ctx context.Context, field gr
 	}
 	res := resTmp.(*model.BranchDeleteStatus)
 	fc.Result = res
-	return ec.marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchDeleteStatus(ctx, field.Selections, res)
+	return ec.marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchDeleteStatus(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_fetchFromRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3503,7 +3503,7 @@ func (ec *executionContext) _Mutation_fetchFromRemote(ctx context.Context, field
 	}
 	res := resTmp.(*model.FetchResult)
 	fc.Result = res
-	return ec.marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchResult(ctx, field.Selections, res)
+	return ec.marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_pullFromRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3545,7 +3545,7 @@ func (ec *executionContext) _Mutation_pullFromRemote(ctx context.Context, field
 	}
 	res := resTmp.(*model.PullResult)
 	fc.Result = res
-	return ec.marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐPullResult(ctx, field.Selections, res)
+	return ec.marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐPullResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_stageItem(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -3741,7 +3741,7 @@ func (ec *executionContext) _Mutation_commitChanges(ctx context.Context, field g
 	fc.Args = args
 	resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
 		ctx = rctx // use context from middleware stack in children
-		return ec.resolvers.Mutation().CommitChanges(rctx, args["repoId"].(string), args["commitMessage"].(string))
+		return ec.resolvers.Mutation().CommitChanges(rctx, args["repoId"].(string), args["commitMessage"].([]*string))
 	})
 	if err != nil {
 		ec.Error(ctx, err)
@@ -3923,7 +3923,7 @@ func (ec *executionContext) _Mutation_deleteRepo(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.DeleteStatus)
 	fc.Result = res
-	return ec.marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐDeleteStatus(ctx, field.Selections, res)
+	return ec.marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐDeleteStatus(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_updateRepoName(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4007,7 +4007,7 @@ func (ec *executionContext) _Mutation_addRemote(ctx context.Context, field graph
 	}
 	res := resTmp.(*model.RemoteMutationResult)
 	fc.Result = res
-	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
+	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_deleteRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4049,7 +4049,7 @@ func (ec *executionContext) _Mutation_deleteRemote(ctx context.Context, field gr
 	}
 	res := resTmp.(*model.RemoteMutationResult)
 	fc.Result = res
-	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
+	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Mutation_editRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4091,7 +4091,7 @@ func (ec *executionContext) _Mutation_editRemote(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.RemoteMutationResult)
 	fc.Result = res
-	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
+	return ec.marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _PullResult_status(ctx context.Context, field graphql.CollectedField, obj *model.PullResult) (ret graphql.Marshaler) {
@@ -4196,7 +4196,7 @@ func (ec *executionContext) _Query_healthCheck(ctx context.Context, field graphq
 	}
 	res := resTmp.(*model.HealthCheckParams)
 	fc.Result = res
-	return ec.marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐHealthCheckParams(ctx, field.Selections, res)
+	return ec.marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐHealthCheckParams(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_fetchRepo(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4231,7 +4231,7 @@ func (ec *executionContext) _Query_fetchRepo(ctx context.Context, field graphql.
 	}
 	res := resTmp.(*model.FetchRepoParams)
 	fc.Result = res
-	return ec.marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchRepoParams(ctx, field.Selections, res)
+	return ec.marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchRepoParams(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitRepoStatus(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4273,7 +4273,7 @@ func (ec *executionContext) _Query_gitRepoStatus(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.GitRepoStatusResults)
 	fc.Result = res
-	return ec.marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitRepoStatusResults(ctx, field.Selections, res)
+	return ec.marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitRepoStatusResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitFolderContent(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4315,7 +4315,7 @@ func (ec *executionContext) _Query_gitFolderContent(ctx context.Context, field g
 	}
 	res := resTmp.(*model.GitFolderContentResults)
 	fc.Result = res
-	return ec.marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitFolderContentResults(ctx, field.Selections, res)
+	return ec.marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitFolderContentResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitCommitLogs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4357,7 +4357,7 @@ func (ec *executionContext) _Query_gitCommitLogs(ctx context.Context, field grap
 	}
 	res := resTmp.(*model.GitCommitLogResults)
 	fc.Result = res
-	return ec.marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitLogResults(ctx, field.Selections, res)
+	return ec.marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitLogResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitCommitFiles(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4399,7 +4399,7 @@ func (ec *executionContext) _Query_gitCommitFiles(ctx context.Context, field gra
 	}
 	res := resTmp.([]*model.GitCommitFileResult)
 	fc.Result = res
-	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
+	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_searchCommitLogs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4441,7 +4441,7 @@ func (ec *executionContext) _Query_searchCommitLogs(ctx context.Context, field g
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_codeFileDetails(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4483,7 +4483,7 @@ func (ec *executionContext) _Query_codeFileDetails(ctx context.Context, field gr
 	}
 	res := resTmp.(*model.CodeFileType)
 	fc.Result = res
-	return ec.marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐCodeFileType(ctx, field.Selections, res)
+	return ec.marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐCodeFileType(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitChanges(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4525,7 +4525,7 @@ func (ec *executionContext) _Query_gitChanges(ctx context.Context, field graphql
 	}
 	res := resTmp.(*model.GitChangeResults)
 	fc.Result = res
-	return ec.marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitChangeResults(ctx, field.Selections, res)
+	return ec.marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitChangeResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitUnPushedCommits(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4567,7 +4567,7 @@ func (ec *executionContext) _Query_gitUnPushedCommits(ctx context.Context, field
 	}
 	res := resTmp.(*model.UnPushedCommitResult)
 	fc.Result = res
-	return ec.marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐUnPushedCommitResult(ctx, field.Selections, res)
+	return ec.marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐUnPushedCommitResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_gitFileLineChanges(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4609,7 +4609,7 @@ func (ec *executionContext) _Query_gitFileLineChanges(ctx context.Context, field
 	}
 	res := resTmp.(*model.FileLineChangeResult)
 	fc.Result = res
-	return ec.marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFileLineChangeResult(ctx, field.Selections, res)
+	return ec.marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFileLineChangeResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_settingsData(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4644,7 +4644,7 @@ func (ec *executionContext) _Query_settingsData(ctx context.Context, field graph
 	}
 	res := resTmp.(*model.SettingsDataResults)
 	fc.Result = res
-	return ec.marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐSettingsDataResults(ctx, field.Selections, res)
+	return ec.marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐSettingsDataResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_commitCompare(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4686,7 +4686,7 @@ func (ec *executionContext) _Query_commitCompare(ctx context.Context, field grap
 	}
 	res := resTmp.([]*model.GitCommitFileResult)
 	fc.Result = res
-	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
+	return ec.marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_branchCompare(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4728,7 +4728,7 @@ func (ec *executionContext) _Query_branchCompare(ctx context.Context, field grap
 	}
 	res := resTmp.([]*model.BranchCompareResults)
 	fc.Result = res
-	return ec.marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx, field.Selections, res)
+	return ec.marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query_getRemote(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4770,7 +4770,7 @@ func (ec *executionContext) _Query_getRemote(ctx context.Context, field graphql.
 	}
 	res := resTmp.([]*model.RemoteDetails)
 	fc.Result = res
-	return ec.marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx, field.Selections, res)
+	return ec.marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
@@ -4911,7 +4911,7 @@ func (ec *executionContext) _UnPushedCommitResult_gitCommits(ctx context.Context
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) {
@@ -6064,7 +6064,7 @@ func (ec *executionContext) _branchCompareResults_commits(ctx context.Context, f
 	}
 	res := resTmp.([]*model.GitCommits)
 	fc.Result = res
-	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
+	return ec.marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, field.Selections, res)
 }
 
 func (ec *executionContext) _codeFileType_fileData(ctx context.Context, field graphql.CollectedField, obj *model.CodeFileType) (ret graphql.Marshaler) {
@@ -8017,11 +8017,11 @@ func (ec *executionContext) _settingsDataResults(ctx context.Context, sel ast.Se
 
 // region    ***************************** type.gotpl *****************************
 
-func (ec *executionContext) marshalNAddRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v model.AddRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNAddRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v model.AddRepoParams) graphql.Marshaler {
 	return ec._AddRepoParams(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.AddRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNAddRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐAddRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.AddRepoParams) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8046,11 +8046,11 @@ func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.Se
 	return res
 }
 
-func (ec *executionContext) marshalNBranchDeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.BranchDeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNBranchDeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.BranchDeleteStatus) graphql.Marshaler {
 	return ec._BranchDeleteStatus(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.BranchDeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.BranchDeleteStatus) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8060,11 +8060,11 @@ func (ec *executionContext) marshalNBranchDeleteStatus2ᚖgithubᚗcomᚋneel199
 	return ec._BranchDeleteStatus(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNFetchRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v model.FetchRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchRepoParams2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v model.FetchRepoParams) graphql.Marshaler {
 	return ec._FetchRepoParams(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.FetchRepoParams) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchRepoParams(ctx context.Context, sel ast.SelectionSet, v *model.FetchRepoParams) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8074,11 +8074,11 @@ func (ec *executionContext) marshalNFetchRepoParams2ᚖgithubᚗcomᚋneel1996
 	return ec._FetchRepoParams(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNFetchResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v model.FetchResult) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v model.FetchResult) graphql.Marshaler {
 	return ec._FetchResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v *model.FetchResult) graphql.Marshaler {
+func (ec *executionContext) marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFetchResult(ctx context.Context, sel ast.SelectionSet, v *model.FetchResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8088,11 +8088,11 @@ func (ec *executionContext) marshalNFetchResult2ᚖgithubᚗcomᚋneel1996ᚋgit
 	return ec._FetchResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNGitCommitLogResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v model.GitCommitLogResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitCommitLogResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v model.GitCommitLogResults) graphql.Marshaler {
 	return ec._GitCommitLogResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitLogResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitLogResults(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitLogResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8102,11 +8102,11 @@ func (ec *executionContext) marshalNGitCommitLogResults2ᚖgithubᚗcomᚋneel19
 	return ec._GitCommitLogResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNGitFolderContentResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v model.GitFolderContentResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitFolderContentResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v model.GitFolderContentResults) graphql.Marshaler {
 	return ec._GitFolderContentResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v *model.GitFolderContentResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitFolderContentResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitFolderContentResults(ctx context.Context, sel ast.SelectionSet, v *model.GitFolderContentResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8116,11 +8116,11 @@ func (ec *executionContext) marshalNGitFolderContentResults2ᚖgithubᚗcomᚋne
 	return ec._GitFolderContentResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNGitRepoStatusResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v model.GitRepoStatusResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitRepoStatusResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v model.GitRepoStatusResults) graphql.Marshaler {
 	return ec._GitRepoStatusResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v *model.GitRepoStatusResults) graphql.Marshaler {
+func (ec *executionContext) marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitRepoStatusResults(ctx context.Context, sel ast.SelectionSet, v *model.GitRepoStatusResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8130,11 +8130,11 @@ func (ec *executionContext) marshalNGitRepoStatusResults2ᚖgithubᚗcomᚋneel1
 	return ec._GitRepoStatusResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNHealthCheckParams2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v model.HealthCheckParams) graphql.Marshaler {
+func (ec *executionContext) marshalNHealthCheckParams2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v model.HealthCheckParams) graphql.Marshaler {
 	return ec._HealthCheckParams(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v *model.HealthCheckParams) graphql.Marshaler {
+func (ec *executionContext) marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐHealthCheckParams(ctx context.Context, sel ast.SelectionSet, v *model.HealthCheckParams) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8144,11 +8144,11 @@ func (ec *executionContext) marshalNHealthCheckParams2ᚖgithubᚗcomᚋneel1996
 	return ec._HealthCheckParams(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNPullResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v model.PullResult) graphql.Marshaler {
+func (ec *executionContext) marshalNPullResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v model.PullResult) graphql.Marshaler {
 	return ec._PullResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v *model.PullResult) graphql.Marshaler {
+func (ec *executionContext) marshalNPullResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐPullResult(ctx context.Context, sel ast.SelectionSet, v *model.PullResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8203,11 +8203,11 @@ func (ec *executionContext) marshalNString2ᚕᚖstring(ctx context.Context, sel
 	return ret
 }
 
-func (ec *executionContext) marshalNUnPushedCommitResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v model.UnPushedCommitResult) graphql.Marshaler {
+func (ec *executionContext) marshalNUnPushedCommitResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v model.UnPushedCommitResult) graphql.Marshaler {
 	return ec._UnPushedCommitResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v *model.UnPushedCommitResult) graphql.Marshaler {
+func (ec *executionContext) marshalNUnPushedCommitResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐUnPushedCommitResult(ctx context.Context, sel ast.SelectionSet, v *model.UnPushedCommitResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8446,7 +8446,7 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a
 	return res
 }
 
-func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v []*model.BranchCompareResults) graphql.Marshaler {
+func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v []*model.BranchCompareResults) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8470,7 +8470,7 @@ func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋne
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx, sel, v[i])
+			ret[i] = ec.marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8483,11 +8483,11 @@ func (ec *executionContext) marshalNbranchCompareResults2ᚕᚖgithubᚗcomᚋne
 	return ret
 }
 
-func (ec *executionContext) marshalNcodeFileType2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v model.CodeFileType) graphql.Marshaler {
+func (ec *executionContext) marshalNcodeFileType2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v model.CodeFileType) graphql.Marshaler {
 	return ec._codeFileType(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v *model.CodeFileType) graphql.Marshaler {
+func (ec *executionContext) marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐCodeFileType(ctx context.Context, sel ast.SelectionSet, v *model.CodeFileType) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8497,11 +8497,11 @@ func (ec *executionContext) marshalNcodeFileType2ᚖgithubᚗcomᚋneel1996ᚋgi
 	return ec._codeFileType(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNdeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.DeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNdeleteStatus2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v model.DeleteStatus) graphql.Marshaler {
 	return ec._deleteStatus(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.DeleteStatus) graphql.Marshaler {
+func (ec *executionContext) marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐDeleteStatus(ctx context.Context, sel ast.SelectionSet, v *model.DeleteStatus) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8511,11 +8511,11 @@ func (ec *executionContext) marshalNdeleteStatus2ᚖgithubᚗcomᚋneel1996ᚋgi
 	return ec._deleteStatus(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNfileLineChangeResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v model.FileLineChangeResult) graphql.Marshaler {
+func (ec *executionContext) marshalNfileLineChangeResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v model.FileLineChangeResult) graphql.Marshaler {
 	return ec._fileLineChangeResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v *model.FileLineChangeResult) graphql.Marshaler {
+func (ec *executionContext) marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐFileLineChangeResult(ctx context.Context, sel ast.SelectionSet, v *model.FileLineChangeResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8525,11 +8525,11 @@ func (ec *executionContext) marshalNfileLineChangeResult2ᚖgithubᚗcomᚋneel1
 	return ec._fileLineChangeResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNgitChangeResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v model.GitChangeResults) graphql.Marshaler {
+func (ec *executionContext) marshalNgitChangeResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v model.GitChangeResults) graphql.Marshaler {
 	return ec._gitChangeResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v *model.GitChangeResults) graphql.Marshaler {
+func (ec *executionContext) marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitChangeResults(ctx context.Context, sel ast.SelectionSet, v *model.GitChangeResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8539,7 +8539,7 @@ func (ec *executionContext) marshalNgitChangeResults2ᚖgithubᚗcomᚋneel1996
 	return ec._gitChangeResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommitFileResult) graphql.Marshaler {
+func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommitFileResult) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8563,7 +8563,7 @@ func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋnee
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx, sel, v[i])
+			ret[i] = ec.marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8576,7 +8576,7 @@ func (ec *executionContext) marshalNgitCommitFileResult2ᚕᚖgithubᚗcomᚋnee
 	return ret
 }
 
-func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
+func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8600,7 +8600,7 @@ func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
+			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8613,7 +8613,7 @@ func (ec *executionContext) marshalNgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 	return ret
 }
 
-func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v []*model.RemoteDetails) graphql.Marshaler {
+func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v []*model.RemoteDetails) graphql.Marshaler {
 	ret := make(graphql.Array, len(v))
 	var wg sync.WaitGroup
 	isLen1 := len(v) == 1
@@ -8637,7 +8637,7 @@ func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx, sel, v[i])
+			ret[i] = ec.marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -8650,11 +8650,11 @@ func (ec *executionContext) marshalNremoteDetails2ᚕᚖgithubᚗcomᚋneel1996
 	return ret
 }
 
-func (ec *executionContext) marshalNremoteMutationResult2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v model.RemoteMutationResult) graphql.Marshaler {
+func (ec *executionContext) marshalNremoteMutationResult2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v model.RemoteMutationResult) graphql.Marshaler {
 	return ec._remoteMutationResult(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v *model.RemoteMutationResult) graphql.Marshaler {
+func (ec *executionContext) marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteMutationResult(ctx context.Context, sel ast.SelectionSet, v *model.RemoteMutationResult) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8664,11 +8664,11 @@ func (ec *executionContext) marshalNremoteMutationResult2ᚖgithubᚗcomᚋneel1
 	return ec._remoteMutationResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalNsettingsDataResults2githubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v model.SettingsDataResults) graphql.Marshaler {
+func (ec *executionContext) marshalNsettingsDataResults2githubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v model.SettingsDataResults) graphql.Marshaler {
 	return ec._settingsDataResults(ctx, sel, &v)
 }
 
-func (ec *executionContext) marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v *model.SettingsDataResults) graphql.Marshaler {
+func (ec *executionContext) marshalNsettingsDataResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐSettingsDataResults(ctx context.Context, sel ast.SelectionSet, v *model.SettingsDataResults) graphql.Marshaler {
 	if v == nil {
 		if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
 			ec.Errorf(ctx, "must not be null")
@@ -8702,21 +8702,6 @@ func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast
 	return graphql.MarshalBoolean(*v)
 }
 
-func (ec *executionContext) unmarshalOFloat2ᚖfloat64(ctx context.Context, v interface{}) (*float64, error) {
-	if v == nil {
-		return nil, nil
-	}
-	res, err := graphql.UnmarshalFloat(v)
-	return &res, graphql.ErrorOnPath(ctx, err)
-}
-
-func (ec *executionContext) marshalOFloat2ᚖfloat64(ctx context.Context, sel ast.SelectionSet, v *float64) graphql.Marshaler {
-	if v == nil {
-		return graphql.Null
-	}
-	return graphql.MarshalFloat(*v)
-}
-
 func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) {
 	if v == nil {
 		return nil, nil
@@ -8966,21 +8951,21 @@ func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgen
 	return ec.___Type(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v *model.BranchCompareResults) graphql.Marshaler {
+func (ec *executionContext) marshalObranchCompareResults2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐBranchCompareResults(ctx context.Context, sel ast.SelectionSet, v *model.BranchCompareResults) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
 	return ec._branchCompareResults(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitFileResult) graphql.Marshaler {
+func (ec *executionContext) marshalOgitCommitFileResult2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommitFileResult(ctx context.Context, sel ast.SelectionSet, v *model.GitCommitFileResult) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
 	return ec._gitCommitFileResult(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
+func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v []*model.GitCommits) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
@@ -9007,7 +8992,7 @@ func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 			if !isLen1 {
 				defer wg.Done()
 			}
-			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
+			ret[i] = ec.marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx, sel, v[i])
 		}
 		if isLen1 {
 			f(i)
@@ -9020,14 +9005,14 @@ func (ec *executionContext) marshalOgitCommits2ᚕᚖgithubᚗcomᚋneel1996ᚋg
 	return ret
 }
 
-func (ec *executionContext) marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v *model.GitCommits) graphql.Marshaler {
+func (ec *executionContext) marshalOgitCommits2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐGitCommits(ctx context.Context, sel ast.SelectionSet, v *model.GitCommits) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
 	return ec._gitCommits(ctx, sel, v)
 }
 
-func (ec *executionContext) marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚑserverᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v *model.RemoteDetails) graphql.Marshaler {
+func (ec *executionContext) marshalOremoteDetails2ᚖgithubᚗcomᚋneel1996ᚋgitconvexᚋgraphᚋmodelᚐRemoteDetails(ctx context.Context, sel ast.SelectionSet, v *model.RemoteDetails) graphql.Marshaler {
 	if v == nil {
 		return graphql.Null
 	}
diff --git a/graph/model/aux_models.go b/graph/model/aux_models.go
index 43b11b9..53887b7 100644
--- a/graph/model/aux_models.go
+++ b/graph/model/aux_models.go
@@ -18,3 +18,9 @@ type NewRepoInputs struct {
 	UserName    *string
 	Password    *string
 }
+
+type ListOfBranches struct {
+	CurrentBranch string
+	BranchList    []string
+	AllBranchList []string
+}
diff --git a/graph/model/models_gen.go b/graph/model/models_gen.go
index 125fe1e..2f45154 100644
--- a/graph/model/models_gen.go
+++ b/graph/model/models_gen.go
@@ -41,7 +41,7 @@ type FetchResult struct {
 // Returns the total number of commits in the repo and the array of 10 commit log entries
 type GitCommitLogResults struct {
 	// Total number of commits tracked by the branch
-	TotalCommits *float64 `json:"totalCommits"`
+	TotalCommits *int `json:"totalCommits"`
 	// Array of commit log entries `gitCommits`
 	Commits []*GitCommits `json:"commits"`
 }
@@ -70,7 +70,7 @@ type GitRepoStatusResults struct {
 	// Remote host name based on the remote URL (E.g: https://github.com/github/repo.git -> Github)
 	GitRemoteHost *string `json:"gitRemoteHost"`
 	// Total number of commits tracked by the current branch
-	GitTotalCommits *float64 `json:"gitTotalCommits"`
+	GitTotalCommits *int `json:"gitTotalCommits"`
 	// The latest commit (HEAD commit)
 	GitLatestCommit *string `json:"gitLatestCommit"`
 	// Total number of files tracked by git repo
diff --git a/graph/resolver.go b/graph/resolver.go
index a25c09c..35effa5 100644
--- a/graph/resolver.go
+++ b/graph/resolver.go
@@ -1,7 +1,29 @@
 package graph
 
-// This file will not be regenerated automatically.
-//
-// It serves as dependency injection for your app, add any dependencies you require here.
+import (
+	"context"
+	"github.com/neel1996/gitconvex/controller"
+	"github.com/neel1996/gitconvex/git/middleware"
+	initialize "github.com/neel1996/gitconvex/init"
+	"github.com/neel1996/gitconvex/models"
+	"github.com/neel1996/gitconvex/validator"
+)
 
 type Resolver struct{}
+
+func (r *Resolver) BranchController(ctx context.Context, repo middleware.Repository) controller.BranchController {
+	repoValidator := validator.NewRepoValidator()
+	if repoValidator.Validate(repo) != nil {
+		ctx.Done()
+		return nil
+	}
+	branchObject := initialize.NewInitBranch(repo)
+
+	branchModel := models.Branch{
+		Add:      branchObject.BranchAdd(),
+		Checkout: branchObject.BranchCheckout(),
+		Delete:   branchObject.BranchDelete(),
+	}
+
+	return controller.NewBranchController(branchModel)
+}
diff --git a/graph/schema.graphqls b/graph/schema.graphqls
index 98c072a..2ee7888 100644
--- a/graph/schema.graphqls
+++ b/graph/schema.graphqls
@@ -43,7 +43,7 @@ type GitRepoStatusResults {
     "Remote host name based on the remote URL (E.g: https://github.com/github/repo.git -> Github)"
     gitRemoteHost: String
     "Total number of commits tracked by the current branch"
-    gitTotalCommits: Float
+    gitTotalCommits: Int
     "The latest commit (HEAD commit)"
     gitLatestCommit: String
     "Total number of files tracked by git repo"
@@ -66,7 +66,7 @@ Returns the total number of commits in the repo and the array of 10 commit log e
 """
 type GitCommitLogResults {
     "Total number of commits tracked by the branch"
-    totalCommits: Float
+    totalCommits: Int
     "Array of commit log entries `gitCommits`"
     commits: [gitCommits]
 }
@@ -436,7 +436,7 @@ type Mutation {
         "The UUID of the repo. It will be available in the JSON data file"
         repoId: String!,
         "The message for the commit"
-        commitMessage: String!
+        commitMessage: [String]!
     ): String!
 
     "Pushes the commits to the remote"
diff --git a/graph/schema.resolvers.go b/graph/schema.resolvers.go
index cbade0d..9ec0cb4 100644
--- a/graph/schema.resolvers.go
+++ b/graph/schema.resolvers.go
@@ -7,10 +7,17 @@ import (
 	"context"
 
 	"github.com/neel1996/gitconvex/api"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/controller"
 	"github.com/neel1996/gitconvex/git"
+	"github.com/neel1996/gitconvex/git/commit"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/git/remote"
 	"github.com/neel1996/gitconvex/global"
 	"github.com/neel1996/gitconvex/graph/generated"
 	"github.com/neel1996/gitconvex/graph/model"
+	initialize "github.com/neel1996/gitconvex/init"
+	"github.com/neel1996/gitconvex/utils"
 )
 
 func (r *mutationResolver) AddRepo(ctx context.Context, repoName string, repoPath string, cloneSwitch bool, repoURL *string, initSwitch bool, authOption string, sshKeyPath *string, userName *string, password *string) (*model.AddRepoParams, error) {
@@ -37,14 +44,13 @@ func (r *mutationResolver) AddBranch(ctx context.Context, repoID string, branchN
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
-	if repo.GitRepo == nil {
-		logger.Log("Repo is invalid. Branch addition failed", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return global.BranchAddError, nil
 	}
 
-	var addBranch git.AddBranch
-	addBranch = git.NewAddBranch(repo.GitRepo, branchName, false, nil)
-	return addBranch.AddBranch(), nil
+	return branchController.GitAddBranch(branchName, false, nil)
 }
 
 func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, branchName string) (string, error) {
@@ -57,17 +63,13 @@ func (r *mutationResolver) CheckoutBranch(ctx context.Context, repoID string, br
 	go repoObject.Repo(repoChan)
 
 	repo := <-repoChan
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repository is invalid or HEAD is null", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return global.BranchCheckoutError, nil
 	}
 
-	var checkoutObject git.BranchCheckoutInterface
-	checkoutObject = git.BranchCheckoutInputs{
-		Repo:       repo.GitRepo,
-		BranchName: branchName,
-	}
-	return checkoutObject.CheckoutBranch(), nil
+	return branchController.GitCheckoutBranch(branchName)
 }
 
 func (r *mutationResolver) DeleteBranch(ctx context.Context, repoID string, branchName string, forceFlag bool) (*model.BranchDeleteStatus, error) {
@@ -78,19 +80,15 @@ func (r *mutationResolver) DeleteBranch(ctx context.Context, repoID string, bran
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is null", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return &model.BranchDeleteStatus{
 			Status: global.BranchDeleteError,
 		}, nil
 	}
 
-	var deleteBranchObject git.DeleteBranchInterface
-	deleteBranchObject = git.DeleteBranchInputs{
-		Repo:       repo.GitRepo,
-		BranchName: branchName,
-	}
-	return deleteBranchObject.DeleteBranch(), nil
+	return branchController.GitDeleteBranch(branchName)
 }
 
 func (r *mutationResolver) FetchFromRemote(ctx context.Context, repoID string, remoteURL *string, remoteBranch *string) (*model.FetchResult, error) {
@@ -111,16 +109,12 @@ func (r *mutationResolver) FetchFromRemote(ctx context.Context, repoID string, r
 		}, nil
 	}
 
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo.GitRepo,
-		RemoteURL: *remoteURL,
-	}
+	remoteName := initialize.RemoteObjects(ctx).RemoteName
 
 	var fetchObject git.FetchInterface
 	fetchObject = git.FetchStruct{
 		Repo:         repo.GitRepo,
-		RemoteName:   remoteDataObject.GetRemoteName(),
+		RemoteName:   remoteName.GetRemoteNameWithUrl(),
 		RepoPath:     repo.RepoPath,
 		RemoteURL:    *remoteURL,
 		RemoteBranch: *remoteBranch,
@@ -243,7 +237,7 @@ func (r *mutationResolver) StageAllItems(ctx context.Context, repoID string) (st
 	return stageAllObject.StageAllItems(), nil
 }
 
-func (r *mutationResolver) CommitChanges(ctx context.Context, repoID string, commitMessage string) (string, error) {
+func (r *mutationResolver) CommitChanges(ctx context.Context, repoID string, commitMessage []*string) (string, error) {
 	logger.Log("Initiating commit changes request", global.StatusInfo)
 
 	repoChan := make(chan git.RepoDetails)
@@ -252,14 +246,10 @@ func (r *mutationResolver) CommitChanges(ctx context.Context, repoID string, com
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
 
-	var commitObject git.CommitInterface
-	commitObject = git.CommitStruct{
-		Repo:          repo.GitRepo,
-		CommitMessage: commitMessage,
-		RepoPath:      repo.RepoPath,
-	}
+	commitChanges := commit.NewCommitChanges(middleware.NewRepository(repo.GitRepo), utils.GenerateNonPointerArrayFrom(commitMessage))
+	commitOperation := commit.Operation{Changes: commitChanges}
 
-	return commitObject.CommitChanges(), nil
+	return commitOperation.GitCommitChange()
 }
 
 func (r *mutationResolver) PushToRemote(ctx context.Context, repoID string, remoteHost string, branch string) (string, error) {
@@ -271,13 +261,7 @@ func (r *mutationResolver) PushToRemote(ctx context.Context, repoID string, remo
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
 
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo.GitRepo,
-		RemoteURL: remoteHost,
-	}
-
-	remoteName := remoteDataObject.GetRemoteName()
+	remoteName := initialize.RemoteObjects(ctx).RemoteName.GetRemoteNameWithUrl()
 
 	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil || remoteName == "" {
 		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
@@ -332,13 +316,10 @@ func (r *mutationResolver) AddRemote(ctx context.Context, repoID string, remoteN
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	var addRemoteObject git.AddRemoteInterface
-	addRemoteObject = git.AddRemoteStruct{
-		Repo:       repo.GitRepo,
-		RemoteName: remoteName,
-		RemoteURL:  remoteURL,
-	}
-	return addRemoteObject.AddRemote(), nil
+	addRemote := initialize.RemoteObjects(ctx).AddRemote
+	remoteObject := remote.Operation{Add: addRemote}
+
+	return remoteObject.GitAddRemote()
 }
 
 func (r *mutationResolver) DeleteRemote(ctx context.Context, repoID string, remoteName string) (*model.RemoteMutationResult, error) {
@@ -354,12 +335,13 @@ func (r *mutationResolver) DeleteRemote(ctx context.Context, repoID string, remo
 		return &model.RemoteMutationResult{Status: global.RemoteAddError}, nil
 	}
 
-	var addRemoteObject git.DeleteRemoteInterface
-	addRemoteObject = &git.DeleteRemoteStruct{
-		Repo:       repo.GitRepo,
-		RemoteName: remoteName,
+	deleteRemote := initialize.RemoteObjects(ctx).DeleteRemote
+
+	remoteObject := remote.Operation{
+		Delete: deleteRemote,
 	}
-	return addRemoteObject.DeleteRemote(), nil
+
+	return remoteObject.GitDeleteRemote()
 }
 
 func (r *mutationResolver) EditRemote(ctx context.Context, repoID string, remoteName string, remoteURL string) (*model.RemoteMutationResult, error) {
@@ -373,16 +355,15 @@ func (r *mutationResolver) EditRemote(ctx context.Context, repoID string, remote
 
 	if repo.GitRepo == nil {
 		logger.Log("Repo is invalid", global.StatusError)
-		return &model.RemoteMutationResult{Status: global.RemoteEditError}, nil
+		return &model.RemoteMutationResult{Status: constants.RemoteEditError.Error()}, nil
 	}
 
-	var editRemoteObject git.RemoteEditInterface
-	editRemoteObject = git.RemoteEditStruct{
-		Repo:       repo.GitRepo,
-		RemoteName: remoteName,
-		RemoteUrl:  remoteURL,
+	editRemote := initialize.RemoteObjects(ctx).EditRemote
+	editRemoteObject := remote.Operation{
+		Edit: editRemote,
 	}
-	return editRemoteObject.EditRemoteUrl(), nil
+
+	return editRemoteObject.GitEditRemote()
 }
 
 func (r *queryResolver) HealthCheck(ctx context.Context) (*model.HealthCheckParams, error) {
@@ -433,84 +414,19 @@ func (r *queryResolver) GitFolderContent(ctx context.Context, repoID string, dir
 func (r *queryResolver) GitCommitLogs(ctx context.Context, repoID string, referenceCommit string) (*model.GitCommitLogResults, error) {
 	logger.Log("Initiating get commit logs request", global.StatusInfo)
 
-	repoChan := make(chan git.RepoDetails)
-	var repoObject git.RepoInterface
-	repoObject = git.RepoStruct{RepoId: repoID}
-	go repoObject.Repo(repoChan)
-	repo := <-repoChan
-
-	var commitLogObject git.CommitLogInterface
-	commitLogObject = git.CommitLogStruct{
-		Repo:            repo.GitRepo,
-		ReferenceCommit: referenceCommit,
-	}
-
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
-		return &model.GitCommitLogResults{
-			TotalCommits: nil,
-			Commits:      nil,
-		}, nil
-	}
-	return commitLogObject.CommitLogs(), nil
+	return controller.NewCommitLogController(repoID, referenceCommit).GetCommitLogs()
 }
 
 func (r *queryResolver) GitCommitFiles(ctx context.Context, repoID string, commitHash string) ([]*model.GitCommitFileResult, error) {
 	logger.Log("Initiating get commit files request", global.StatusInfo)
 
-	repoChan := make(chan git.RepoDetails)
-	var repoObject git.RepoInterface
-	repoObject = git.RepoStruct{RepoId: repoID}
-	go repoObject.Repo(repoChan)
-	repo := <-repoChan
-
-	var commitFileListObject git.CommitFileListInterface
-	commitFileListObject = git.CommitFileListStruct{
-		Repo:       repo.GitRepo,
-		CommitHash: commitHash,
-	}
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
-		return []*model.GitCommitFileResult{
-			{
-				Type:     "",
-				FileName: "",
-			},
-		}, nil
-	}
-	return commitFileListObject.CommitFileList(), nil
+	return controller.NewCommitFileHistoryController(repoID, commitHash).GetCommitFileHistory()
 }
 
 func (r *queryResolver) SearchCommitLogs(ctx context.Context, repoID string, searchType string, searchKey string) ([]*model.GitCommits, error) {
 	logger.Log("Initiating search commit logs request", global.StatusInfo)
 
-	repoChan := make(chan git.RepoDetails)
-	var repoObject git.RepoInterface
-	repoObject = git.RepoStruct{RepoId: repoID}
-	go repoObject.Repo(repoChan)
-	repo := <-repoChan
-
-	var searchCommitObject git.SearchCommitInterface
-
-	searchCommitObject = git.SearchCommitStruct{
-		Repo:       repo.GitRepo,
-		SearchType: searchType,
-		SearchKey:  searchKey,
-	}
-
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
-		return []*model.GitCommits{
-			{
-				Hash:             nil,
-				Author:           nil,
-				CommitTime:       nil,
-				CommitMessage:    nil,
-				CommitFilesCount: nil,
-			},
-		}, nil
-	}
-	return searchCommitObject.SearchCommitLogs(), nil
+	return controller.NewCommitLogSearchController(repoID, searchType, searchKey).GetMatchingCommits()
 }
 
 func (r *queryResolver) CodeFileDetails(ctx context.Context, repoID string, fileName string) (*model.CodeFileType, error) {
@@ -574,12 +490,9 @@ func (r *queryResolver) GitUnPushedCommits(ctx context.Context, repoID string, r
 		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
 		return nil, nil
 	}
-	var remoteDataObject git.RemoteDataInterface
-	remoteDataObject = git.RemoteDataStruct{
-		Repo:      repo.GitRepo,
-		RemoteURL: remoteURL,
-	}
-	remoteName := remoteDataObject.GetRemoteName()
+
+	remoteName := initialize.RemoteObjects(ctx).RemoteName.GetRemoteNameWithUrl()
+
 	remoteRef := remoteName + "/" + remoteBranch
 
 	var unPushedObject git.UnPushedCommitInterface
@@ -665,8 +578,9 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
 	repo := <-repoChan
-	if head, _ := repo.GitRepo.Head(); repo.GitRepo == nil || head == nil {
-		logger.Log("Repo is invalid or HEAD is nil", global.StatusError)
+
+	branchController := r.BranchController(ctx, middleware.NewRepository(repo.GitRepo))
+	if branchController == nil {
 		return []*model.BranchCompareResults{
 			{
 				Date:    "",
@@ -675,13 +589,8 @@ func (r *queryResolver) BranchCompare(ctx context.Context, repoID string, baseBr
 		}, nil
 	}
 
-	var branchCompareObject git.BranchCompareInterface
-	branchCompareObject = git.BranchCompareInputs{
-		Repo:       repo.GitRepo,
-		BaseBranch: baseBranch,
-		DiffBranch: compareBranch,
-	}
-	return branchCompareObject.CompareBranch(), nil
+	return branchController.GitCompareBranches(baseBranch, compareBranch)
+
 }
 
 func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.RemoteDetails, error) {
@@ -691,14 +600,12 @@ func (r *queryResolver) GetRemote(ctx context.Context, repoID string) ([]*model.
 	var repoObject git.RepoInterface
 	repoObject = git.RepoStruct{RepoId: repoID}
 	go repoObject.Repo(repoChan)
-	repo := <-repoChan
+	//repo := <-repoChan
 
-	var remoteObject git.RemoteDataInterface
-	remoteObject = git.RemoteDataStruct{
-		Repo: repo.GitRepo,
-	}
-	allRemoteData := remoteObject.GetAllRemotes()
-	return allRemoteData, nil
+	listRemote := initialize.RemoteObjects(ctx).ListRemote
+	remoteUrlList := remote.Operation{List: listRemote}
+
+	return remoteUrlList.GitGetAllRemote()
 }
 
 // Mutation returns generated.MutationResolver implementation.
diff --git a/init/init.go b/init/init.go
new file mode 100644
index 0000000..187ab4e
--- /dev/null
+++ b/init/init.go
@@ -0,0 +1,5 @@
+package initialize
+
+import "github.com/neel1996/gitconvex/global"
+
+var logger global.Logger
diff --git a/init/init_branch.go b/init/init_branch.go
new file mode 100644
index 0000000..a2b567c
--- /dev/null
+++ b/init/init_branch.go
@@ -0,0 +1,44 @@
+package initialize
+
+import (
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/branch/checkout"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/validator"
+)
+
+var (
+	repoValidator   validator.Validator
+	branchValidator validator.ValidatorWithStringFields
+)
+
+type InitBranch interface {
+	BranchAdd() branch.Add
+	BranchDelete() branch.Delete
+	BranchCheckout() checkout.Factory
+}
+
+type initBranch struct {
+	repo middleware.Repository
+}
+
+func init() {
+	repoValidator = validator.NewRepoValidator()
+	branchValidator = validator.NewBranchValidator()
+}
+
+func (i initBranch) BranchAdd() branch.Add {
+	return branch.NewAddBranch(i.repo, branchValidator)
+}
+
+func (i initBranch) BranchDelete() branch.Delete {
+	return branch.NewDeleteBranch(i.repo, branchValidator)
+}
+
+func (i initBranch) BranchCheckout() checkout.Factory {
+	return checkout.NewCheckoutFactory(i.repo, repoValidator, branchValidator)
+}
+
+func NewInitBranch(repo middleware.Repository) InitBranch {
+	return initBranch{repo: repo}
+}
diff --git a/init/init_remote.go b/init/init_remote.go
new file mode 100644
index 0000000..9494b66
--- /dev/null
+++ b/init/init_remote.go
@@ -0,0 +1,35 @@
+package initialize
+
+import (
+	"context"
+	git2go "github.com/libgit2/git2go/v31"
+	"github.com/neel1996/gitconvex/constants"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/git/remote"
+	"github.com/neel1996/gitconvex/models"
+)
+
+func RemoteObjects(ctx context.Context) models.Remote {
+	r := ctx.Value(constants.Repo).(*git2go.Repository)
+	repo := middleware.NewRepository(r)
+	remoteName := ctx.Value(constants.RemoteName).(string)
+	remoteUrl := ctx.Value(constants.RemoteUrl).(string)
+
+	remoteValidation := remote.NewRemoteValidation(repo)
+
+	listRemote := remote.NewRemoteList(repo, remoteValidation)
+	addRemote := remote.NewAddRemote(repo, remoteName, remoteUrl, remoteValidation)
+	deleteRemote := remote.NewDeleteRemote(repo, remoteName, remoteValidation)
+	editRemote := remote.NewEditRemote(repo, remoteName, remoteUrl, remoteValidation, listRemote)
+	name := remote.NewGetRemoteName(repo, remoteUrl, remoteValidation, listRemote)
+	listRemoteURL := remote.NewRemoteUrlData(repo, remoteValidation, listRemote)
+
+	return models.Remote{
+		AddRemote:     addRemote,
+		DeleteRemote:  deleteRemote,
+		EditRemote:    editRemote,
+		ListRemote:    listRemote,
+		ListRemoteUrl: listRemoteURL,
+		RemoteName:    name,
+	}
+}
diff --git a/mocks/mock_branch.go b/mocks/mock_branch.go
new file mode 100644
index 0000000..baa1728
--- /dev/null
+++ b/mocks/mock_branch.go
@@ -0,0 +1,149 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/branch.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
+)
+
+// MockBranch is a mock of Branch interface.
+type MockBranch struct {
+	ctrl     *gomock.Controller
+	recorder *MockBranchMockRecorder
+}
+
+// MockBranchMockRecorder is the mock recorder for MockBranch.
+type MockBranchMockRecorder struct {
+	mock *MockBranch
+}
+
+// NewMockBranch creates a new mock instance.
+func NewMockBranch(ctrl *gomock.Controller) *MockBranch {
+	mock := &MockBranch{ctrl: ctrl}
+	mock.recorder = &MockBranchMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockBranch) EXPECT() *MockBranchMockRecorder {
+	return m.recorder
+}
+
+// Cmp mocks base method.
+func (m *MockBranch) Cmp(r middleware.Reference) int {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Cmp", r)
+	ret0, _ := ret[0].(int)
+	return ret0
+}
+
+// Cmp indicates an expected call of Cmp.
+func (mr *MockBranchMockRecorder) Cmp(r interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Cmp", reflect.TypeOf((*MockBranch)(nil).Cmp), r)
+}
+
+// Delete mocks base method.
+func (m *MockBranch) Delete() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Delete")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Delete indicates an expected call of Delete.
+func (mr *MockBranchMockRecorder) Delete() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockBranch)(nil).Delete))
+}
+
+// IsNote mocks base method.
+func (m *MockBranch) IsNote() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsNote")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsNote indicates an expected call of IsNote.
+func (mr *MockBranchMockRecorder) IsNote() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsNote", reflect.TypeOf((*MockBranch)(nil).IsNote))
+}
+
+// IsRemote mocks base method.
+func (m *MockBranch) IsRemote() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsRemote")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsRemote indicates an expected call of IsRemote.
+func (mr *MockBranchMockRecorder) IsRemote() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsRemote", reflect.TypeOf((*MockBranch)(nil).IsRemote))
+}
+
+// IsTag mocks base method.
+func (m *MockBranch) IsTag() bool {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "IsTag")
+	ret0, _ := ret[0].(bool)
+	return ret0
+}
+
+// IsTag indicates an expected call of IsTag.
+func (mr *MockBranchMockRecorder) IsTag() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTag", reflect.TypeOf((*MockBranch)(nil).IsTag))
+}
+
+// Name mocks base method.
+func (m *MockBranch) Name() (string, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Name")
+	ret0, _ := ret[0].(string)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Name indicates an expected call of Name.
+func (mr *MockBranchMockRecorder) Name() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockBranch)(nil).Name))
+}
+
+// Reference mocks base method.
+func (m *MockBranch) Reference() middleware.Reference {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Reference")
+	ret0, _ := ret[0].(middleware.Reference)
+	return ret0
+}
+
+// Reference indicates an expected call of Reference.
+func (mr *MockBranchMockRecorder) Reference() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reference", reflect.TypeOf((*MockBranch)(nil).Reference))
+}
+
+// Target mocks base method.
+func (m *MockBranch) Target() *git.Oid {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Target")
+	ret0, _ := ret[0].(*git.Oid)
+	return ret0
+}
+
+// Target indicates an expected call of Target.
+func (mr *MockBranchMockRecorder) Target() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Target", reflect.TypeOf((*MockBranch)(nil).Target))
+}
diff --git a/mocks/mock_branch_iterator.go b/mocks/mock_branch_iterator.go
new file mode 100644
index 0000000..db3ba41
--- /dev/null
+++ b/mocks/mock_branch_iterator.go
@@ -0,0 +1,49 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/branch_iterator.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockBranchIterator is a mock of BranchIterator interface.
+type MockBranchIterator struct {
+	ctrl     *gomock.Controller
+	recorder *MockBranchIteratorMockRecorder
+}
+
+// MockBranchIteratorMockRecorder is the mock recorder for MockBranchIterator.
+type MockBranchIteratorMockRecorder struct {
+	mock *MockBranchIterator
+}
+
+// NewMockBranchIterator creates a new mock instance.
+func NewMockBranchIterator(ctrl *gomock.Controller) *MockBranchIterator {
+	mock := &MockBranchIterator{ctrl: ctrl}
+	mock.recorder = &MockBranchIteratorMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockBranchIterator) EXPECT() *MockBranchIteratorMockRecorder {
+	return m.recorder
+}
+
+// ForEach mocks base method.
+func (m *MockBranchIterator) ForEach(arg0 func(*git.Branch, git.BranchType) error) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ForEach", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ForEach indicates an expected call of ForEach.
+func (mr *MockBranchIteratorMockRecorder) ForEach(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForEach", reflect.TypeOf((*MockBranchIterator)(nil).ForEach), arg0)
+}
diff --git a/mocks/mock_commit.go b/mocks/mock_commit.go
new file mode 100644
index 0000000..61bb700
--- /dev/null
+++ b/mocks/mock_commit.go
@@ -0,0 +1,135 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/commit.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
+)
+
+// MockCommit is a mock of Commit interface.
+type MockCommit struct {
+	ctrl     *gomock.Controller
+	recorder *MockCommitMockRecorder
+}
+
+// MockCommitMockRecorder is the mock recorder for MockCommit.
+type MockCommitMockRecorder struct {
+	mock *MockCommit
+}
+
+// NewMockCommit creates a new mock instance.
+func NewMockCommit(ctrl *gomock.Controller) *MockCommit {
+	mock := &MockCommit{ctrl: ctrl}
+	mock.recorder = &MockCommitMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockCommit) EXPECT() *MockCommitMockRecorder {
+	return m.recorder
+}
+
+// Author mocks base method.
+func (m *MockCommit) Author() *git.Signature {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Author")
+	ret0, _ := ret[0].(*git.Signature)
+	return ret0
+}
+
+// Author indicates an expected call of Author.
+func (mr *MockCommitMockRecorder) Author() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Author", reflect.TypeOf((*MockCommit)(nil).Author))
+}
+
+// GetGitCommit mocks base method.
+func (m *MockCommit) GetGitCommit() *git.Commit {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetGitCommit")
+	ret0, _ := ret[0].(*git.Commit)
+	return ret0
+}
+
+// GetGitCommit indicates an expected call of GetGitCommit.
+func (mr *MockCommitMockRecorder) GetGitCommit() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitCommit", reflect.TypeOf((*MockCommit)(nil).GetGitCommit))
+}
+
+// Id mocks base method.
+func (m *MockCommit) Id() *git.Oid {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Id")
+	ret0, _ := ret[0].(*git.Oid)
+	return ret0
+}
+
+// Id indicates an expected call of Id.
+func (mr *MockCommitMockRecorder) Id() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Id", reflect.TypeOf((*MockCommit)(nil).Id))
+}
+
+// Message mocks base method.
+func (m *MockCommit) Message() string {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Message")
+	ret0, _ := ret[0].(string)
+	return ret0
+}
+
+// Message indicates an expected call of Message.
+func (mr *MockCommitMockRecorder) Message() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Message", reflect.TypeOf((*MockCommit)(nil).Message))
+}
+
+// Parent mocks base method.
+func (m *MockCommit) Parent(arg0 uint) middleware.Commit {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Parent", arg0)
+	ret0, _ := ret[0].(middleware.Commit)
+	return ret0
+}
+
+// Parent indicates an expected call of Parent.
+func (mr *MockCommitMockRecorder) Parent(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Parent", reflect.TypeOf((*MockCommit)(nil).Parent), arg0)
+}
+
+// ParentCount mocks base method.
+func (m *MockCommit) ParentCount() uint {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "ParentCount")
+	ret0, _ := ret[0].(uint)
+	return ret0
+}
+
+// ParentCount indicates an expected call of ParentCount.
+func (mr *MockCommitMockRecorder) ParentCount() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ParentCount", reflect.TypeOf((*MockCommit)(nil).ParentCount))
+}
+
+// Tree mocks base method.
+func (m *MockCommit) Tree() (*git.Tree, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Tree")
+	ret0, _ := ret[0].(*git.Tree)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Tree indicates an expected call of Tree.
+func (mr *MockCommitMockRecorder) Tree() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Tree", reflect.TypeOf((*MockCommit)(nil).Tree))
+}
diff --git a/mocks/mock_index.go b/mocks/mock_index.go
new file mode 100644
index 0000000..f6a5064
--- /dev/null
+++ b/mocks/mock_index.go
@@ -0,0 +1,50 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/index.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockIndex is a mock of Index interface.
+type MockIndex struct {
+	ctrl     *gomock.Controller
+	recorder *MockIndexMockRecorder
+}
+
+// MockIndexMockRecorder is the mock recorder for MockIndex.
+type MockIndexMockRecorder struct {
+	mock *MockIndex
+}
+
+// NewMockIndex creates a new mock instance.
+func NewMockIndex(ctrl *gomock.Controller) *MockIndex {
+	mock := &MockIndex{ctrl: ctrl}
+	mock.recorder = &MockIndexMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockIndex) EXPECT() *MockIndexMockRecorder {
+	return m.recorder
+}
+
+// WriteTree mocks base method.
+func (m *MockIndex) WriteTree() (*git.Oid, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "WriteTree")
+	ret0, _ := ret[0].(*git.Oid)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// WriteTree indicates an expected call of WriteTree.
+func (mr *MockIndexMockRecorder) WriteTree() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteTree", reflect.TypeOf((*MockIndex)(nil).WriteTree))
+}
diff --git a/mocks/mock_reference.go b/mocks/mock_reference.go
new file mode 100644
index 0000000..914d7a7
--- /dev/null
+++ b/mocks/mock_reference.go
@@ -0,0 +1,92 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/reference.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockReference is a mock of Reference interface.
+type MockReference struct {
+	ctrl     *gomock.Controller
+	recorder *MockReferenceMockRecorder
+}
+
+// MockReferenceMockRecorder is the mock recorder for MockReference.
+type MockReferenceMockRecorder struct {
+	mock *MockReference
+}
+
+// NewMockReference creates a new mock instance.
+func NewMockReference(ctrl *gomock.Controller) *MockReference {
+	mock := &MockReference{ctrl: ctrl}
+	mock.recorder = &MockReferenceMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockReference) EXPECT() *MockReferenceMockRecorder {
+	return m.recorder
+}
+
+// GetGitReference mocks base method.
+func (m *MockReference) GetGitReference() *git.Reference {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetGitReference")
+	ret0, _ := ret[0].(*git.Reference)
+	return ret0
+}
+
+// GetGitReference indicates an expected call of GetGitReference.
+func (mr *MockReferenceMockRecorder) GetGitReference() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitReference", reflect.TypeOf((*MockReference)(nil).GetGitReference))
+}
+
+// Name mocks base method.
+func (m *MockReference) Name() string {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Name")
+	ret0, _ := ret[0].(string)
+	return ret0
+}
+
+// Name indicates an expected call of Name.
+func (mr *MockReferenceMockRecorder) Name() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Name", reflect.TypeOf((*MockReference)(nil).Name))
+}
+
+// SetTarget mocks base method.
+func (m *MockReference) SetTarget(id *git.Oid, message string) (*git.Reference, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetTarget", id, message)
+	ret0, _ := ret[0].(*git.Reference)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// SetTarget indicates an expected call of SetTarget.
+func (mr *MockReferenceMockRecorder) SetTarget(id, message interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTarget", reflect.TypeOf((*MockReference)(nil).SetTarget), id, message)
+}
+
+// Target mocks base method.
+func (m *MockReference) Target() *git.Oid {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Target")
+	ret0, _ := ret[0].(*git.Oid)
+	return ret0
+}
+
+// Target indicates an expected call of Target.
+func (mr *MockReferenceMockRecorder) Target() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Target", reflect.TypeOf((*MockReference)(nil).Target))
+}
diff --git a/mocks/mock_repository.go b/mocks/mock_repository.go
new file mode 100644
index 0000000..2cfbb92
--- /dev/null
+++ b/mocks/mock_repository.go
@@ -0,0 +1,277 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/repository.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+	middleware "github.com/neel1996/gitconvex/git/middleware"
+)
+
+// MockRepository is a mock of Repository interface.
+type MockRepository struct {
+	ctrl     *gomock.Controller
+	recorder *MockRepositoryMockRecorder
+}
+
+// MockRepositoryMockRecorder is the mock recorder for MockRepository.
+type MockRepositoryMockRecorder struct {
+	mock *MockRepository
+}
+
+// NewMockRepository creates a new mock instance.
+func NewMockRepository(ctrl *gomock.Controller) *MockRepository {
+	mock := &MockRepository{ctrl: ctrl}
+	mock.recorder = &MockRepositoryMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder {
+	return m.recorder
+}
+
+// CheckoutTree mocks base method.
+func (m *MockRepository) CheckoutTree(tree *git.Tree, c *git.CheckoutOptions) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CheckoutTree", tree, c)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// CheckoutTree indicates an expected call of CheckoutTree.
+func (mr *MockRepositoryMockRecorder) CheckoutTree(tree, c interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CheckoutTree", reflect.TypeOf((*MockRepository)(nil).CheckoutTree), tree, c)
+}
+
+// CreateBranch mocks base method.
+func (m *MockRepository) CreateBranch(arg0 string, arg1 *git.Commit, arg2 bool) (*git.Branch, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateBranch", arg0, arg1, arg2)
+	ret0, _ := ret[0].(*git.Branch)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateBranch indicates an expected call of CreateBranch.
+func (mr *MockRepositoryMockRecorder) CreateBranch(arg0, arg1, arg2 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBranch", reflect.TypeOf((*MockRepository)(nil).CreateBranch), arg0, arg1, arg2)
+}
+
+// CreateCommit mocks base method.
+func (m *MockRepository) CreateCommit(s string, signature, signature2 *git.Signature, message string, tree *git.Tree, parents ...*git.Commit) (*git.Oid, error) {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{s, signature, signature2, message, tree}
+	for _, a := range parents {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "CreateCommit", varargs...)
+	ret0, _ := ret[0].(*git.Oid)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateCommit indicates an expected call of CreateCommit.
+func (mr *MockRepositoryMockRecorder) CreateCommit(s, signature, signature2, message, tree interface{}, parents ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	varargs := append([]interface{}{s, signature, signature2, message, tree}, parents...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCommit", reflect.TypeOf((*MockRepository)(nil).CreateCommit), varargs...)
+}
+
+// DefaultSignature mocks base method.
+func (m *MockRepository) DefaultSignature() (*git.Signature, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DefaultSignature")
+	ret0, _ := ret[0].(*git.Signature)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DefaultSignature indicates an expected call of DefaultSignature.
+func (mr *MockRepositoryMockRecorder) DefaultSignature() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultSignature", reflect.TypeOf((*MockRepository)(nil).DefaultSignature))
+}
+
+// DiffTreeToTree mocks base method.
+func (m *MockRepository) DiffTreeToTree(tree, tree2 *git.Tree, options *git.DiffOptions) (*git.Diff, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "DiffTreeToTree", tree, tree2, options)
+	ret0, _ := ret[0].(*git.Diff)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// DiffTreeToTree indicates an expected call of DiffTreeToTree.
+func (mr *MockRepositoryMockRecorder) DiffTreeToTree(tree, tree2, options interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DiffTreeToTree", reflect.TypeOf((*MockRepository)(nil).DiffTreeToTree), tree, tree2, options)
+}
+
+// GetGitRepository mocks base method.
+func (m *MockRepository) GetGitRepository() *git.Repository {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetGitRepository")
+	ret0, _ := ret[0].(*git.Repository)
+	return ret0
+}
+
+// GetGitRepository indicates an expected call of GetGitRepository.
+func (mr *MockRepositoryMockRecorder) GetGitRepository() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGitRepository", reflect.TypeOf((*MockRepository)(nil).GetGitRepository))
+}
+
+// Head mocks base method.
+func (m *MockRepository) Head() (middleware.Reference, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Head")
+	ret0, _ := ret[0].(middleware.Reference)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Head indicates an expected call of Head.
+func (mr *MockRepositoryMockRecorder) Head() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Head", reflect.TypeOf((*MockRepository)(nil).Head))
+}
+
+// Index mocks base method.
+func (m *MockRepository) Index() (middleware.Index, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Index")
+	ret0, _ := ret[0].(middleware.Index)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Index indicates an expected call of Index.
+func (mr *MockRepositoryMockRecorder) Index() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Index", reflect.TypeOf((*MockRepository)(nil).Index))
+}
+
+// LookupBranch mocks base method.
+func (m *MockRepository) LookupBranch(branchName string, branchType git.BranchType) (middleware.Branch, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupBranch", branchName, branchType)
+	ret0, _ := ret[0].(middleware.Branch)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupBranch indicates an expected call of LookupBranch.
+func (mr *MockRepositoryMockRecorder) LookupBranch(branchName, branchType interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupBranch", reflect.TypeOf((*MockRepository)(nil).LookupBranch), branchName, branchType)
+}
+
+// LookupCommit mocks base method.
+func (m *MockRepository) LookupCommit(oid *git.Oid) (*git.Commit, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupCommit", oid)
+	ret0, _ := ret[0].(*git.Commit)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupCommit indicates an expected call of LookupCommit.
+func (mr *MockRepositoryMockRecorder) LookupCommit(oid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupCommit", reflect.TypeOf((*MockRepository)(nil).LookupCommit), oid)
+}
+
+// LookupCommitV2 mocks base method.
+func (m *MockRepository) LookupCommitV2(oid *git.Oid) (middleware.Commit, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupCommitV2", oid)
+	ret0, _ := ret[0].(middleware.Commit)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupCommitV2 indicates an expected call of LookupCommitV2.
+func (mr *MockRepositoryMockRecorder) LookupCommitV2(oid interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupCommitV2", reflect.TypeOf((*MockRepository)(nil).LookupCommitV2), oid)
+}
+
+// LookupTree mocks base method.
+func (m *MockRepository) LookupTree(id *git.Oid) (*git.Tree, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "LookupTree", id)
+	ret0, _ := ret[0].(*git.Tree)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// LookupTree indicates an expected call of LookupTree.
+func (mr *MockRepositoryMockRecorder) LookupTree(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupTree", reflect.TypeOf((*MockRepository)(nil).LookupTree), id)
+}
+
+// NewBranchIterator mocks base method.
+func (m *MockRepository) NewBranchIterator(branchType git.BranchType) (middleware.BranchIterator, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "NewBranchIterator", branchType)
+	ret0, _ := ret[0].(middleware.BranchIterator)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// NewBranchIterator indicates an expected call of NewBranchIterator.
+func (mr *MockRepositoryMockRecorder) NewBranchIterator(branchType interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBranchIterator", reflect.TypeOf((*MockRepository)(nil).NewBranchIterator), branchType)
+}
+
+// Remotes mocks base method.
+func (m *MockRepository) Remotes() middleware.Remotes {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Remotes")
+	ret0, _ := ret[0].(middleware.Remotes)
+	return ret0
+}
+
+// Remotes indicates an expected call of Remotes.
+func (mr *MockRepositoryMockRecorder) Remotes() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Remotes", reflect.TypeOf((*MockRepository)(nil).Remotes))
+}
+
+// SetHead mocks base method.
+func (m *MockRepository) SetHead(name string) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "SetHead", name)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// SetHead indicates an expected call of SetHead.
+func (mr *MockRepositoryMockRecorder) SetHead(name interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetHead", reflect.TypeOf((*MockRepository)(nil).SetHead), name)
+}
+
+// Walk mocks base method.
+func (m *MockRepository) Walk() (middleware.RevWalk, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Walk")
+	ret0, _ := ret[0].(middleware.RevWalk)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// Walk indicates an expected call of Walk.
+func (mr *MockRepositoryMockRecorder) Walk() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Walk", reflect.TypeOf((*MockRepository)(nil).Walk))
+}
diff --git a/mocks/mock_walk.go b/mocks/mock_walk.go
new file mode 100644
index 0000000..bc607c7
--- /dev/null
+++ b/mocks/mock_walk.go
@@ -0,0 +1,77 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: git/middleware/walk.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+	git "github.com/libgit2/git2go/v31"
+)
+
+// MockRevWalk is a mock of RevWalk interface.
+type MockRevWalk struct {
+	ctrl     *gomock.Controller
+	recorder *MockRevWalkMockRecorder
+}
+
+// MockRevWalkMockRecorder is the mock recorder for MockRevWalk.
+type MockRevWalkMockRecorder struct {
+	mock *MockRevWalk
+}
+
+// NewMockRevWalk creates a new mock instance.
+func NewMockRevWalk(ctrl *gomock.Controller) *MockRevWalk {
+	mock := &MockRevWalk{ctrl: ctrl}
+	mock.recorder = &MockRevWalkMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRevWalk) EXPECT() *MockRevWalkMockRecorder {
+	return m.recorder
+}
+
+// Iterate mocks base method.
+func (m *MockRevWalk) Iterate(iterator git.RevWalkIterator) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Iterate", iterator)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Iterate indicates an expected call of Iterate.
+func (mr *MockRevWalkMockRecorder) Iterate(iterator interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Iterate", reflect.TypeOf((*MockRevWalk)(nil).Iterate), iterator)
+}
+
+// Push mocks base method.
+func (m *MockRevWalk) Push(id *git.Oid) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Push", id)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Push indicates an expected call of Push.
+func (mr *MockRevWalkMockRecorder) Push(id interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Push", reflect.TypeOf((*MockRevWalk)(nil).Push), id)
+}
+
+// PushHead mocks base method.
+func (m *MockRevWalk) PushHead() error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "PushHead")
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// PushHead indicates an expected call of PushHead.
+func (mr *MockRevWalkMockRecorder) PushHead() *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushHead", reflect.TypeOf((*MockRevWalk)(nil).PushHead))
+}
diff --git a/models/branch.go b/models/branch.go
new file mode 100644
index 0000000..ba9fffe
--- /dev/null
+++ b/models/branch.go
@@ -0,0 +1,14 @@
+package models
+
+import (
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/branch/checkout"
+)
+
+type Branch struct {
+	Add      branch.Add
+	Checkout checkout.Factory
+	Compare  branch.Compare
+	Delete   branch.Delete
+	List     branch.List
+}
diff --git a/models/remote.go b/models/remote.go
new file mode 100644
index 0000000..9e1e699
--- /dev/null
+++ b/models/remote.go
@@ -0,0 +1,12 @@
+package models
+
+import "github.com/neel1996/gitconvex/git/remote"
+
+type Remote struct {
+	AddRemote     remote.Add
+	DeleteRemote  remote.Delete
+	EditRemote    remote.Edit
+	ListRemote    remote.List
+	RemoteName    remote.Name
+	ListRemoteUrl remote.ListRemoteUrl
+}
diff --git a/server.go b/server.go
index b19e0e4..d12f50a 100644
--- a/server.go
+++ b/server.go
@@ -24,6 +24,8 @@ var (
 
 var logger global.Logger
 
+//go:generate go run ./generators/default_dir_const_gen.go
+
 func main() {
 	versionFlag := flag.Bool("version", false, "To get the current version of gitconvex")
 	portFlag := flag.String("port", "", "To define the port dynamically while starting gitconvex")
diff --git a/test_utils/add_test_branch.go b/test_utils/add_test_branch.go
new file mode 100644
index 0000000..0b31760
--- /dev/null
+++ b/test_utils/add_test_branch.go
@@ -0,0 +1,14 @@
+package test_utils
+
+import (
+	"github.com/neel1996/gitconvex/git/branch"
+	"github.com/neel1996/gitconvex/git/middleware"
+	"github.com/neel1996/gitconvex/validator"
+)
+
+func AddNewTestLocalBranch(repo middleware.Repository, branchName string) {
+	_ = branch.NewAddBranch(
+		repo,
+		validator.NewBranchValidator(),
+	).AddBranch(branchName, false, nil)
+}
diff --git a/tests/beforeAll_git_clone_test.go b/tests/beforeAll_git_clone_test.go
deleted file mode 100644
index 15fff61..0000000
--- a/tests/beforeAll_git_clone_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package tests
-
-import (
-	"github.com/neel1996/gitconvex/git"
-	"github.com/sirupsen/logrus"
-	"os"
-	"testing"
-)
-
-var TestRepo string
-
-func TestMain(m *testing.M) {
-	logger := logrus.New()
-	TestRepo = os.Getenv("GITCONVEX_TEST_REPO")
-	if TestRepo == "" {
-		logger.Error("No test repo passed. Set GITCONVEX_TEST_REPO to a git directory to run integration tests")
-		os.Exit(1)
-	}
-
-	var testObject git.CloneInterface
-	testObject = git.CloneStruct{
-		RepoName:   "",
-		RepoPath:   TestRepo,
-		RepoURL:    "https://github.com/neel1996/starfleet.git",
-		AuthOption: "noauth",
-		SSHKeyPath: "",
-		UserName:   "",
-		Password:   "",
-	}
-	_, err := testObject.CloneRepo()
-	if err != nil {
-		logger.Error("Unable to clone the test repo")
-		os.Exit(2)
-	}
-
-	logger.Info("Initiating integration tests")
-	m.Run()
-}
diff --git a/tests/code_file_view_test.go b/tests/code_file_view_test.go
index b891ba7..94b927b 100644
--- a/tests/code_file_view_test.go
+++ b/tests/code_file_view_test.go
@@ -4,11 +4,12 @@ import (
 	git "github.com/libgit2/git2go/v31"
 	"github.com/neel1996/gitconvex/api"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestCodeFileView(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	type args struct {
 		repo     *git.Repository
diff --git a/tests/git_branch_add_test.go b/tests/git_branch_add_test.go
deleted file mode 100644
index 644d02b..0000000
--- a/tests/git_branch_add_test.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestAddBranch(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		branchName string
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{name: "Git branch add test case", args: struct {
-			repo       *git.Repository
-			branchName string
-		}{repo: r, branchName: "test"}, want: "BRANCH_CREATION_SUCCESS"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			obj := git2.NewAddBranch(tt.args.repo, tt.args.branchName, false, nil)
-			got := obj.AddBranch()
-			assert.Equal(t, tt.want, got)
-
-			git2.DeleteBranchInputs{
-				Repo:       r,
-				BranchName: "test",
-			}.DeleteBranch()
-		})
-	}
-}
diff --git a/tests/git_branch_delete_test.go b/tests/git_branch_delete_test.go
deleted file mode 100644
index b4d6b19..0000000
--- a/tests/git_branch_delete_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/neel1996/gitconvex/graph/model"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestDeleteBranch(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		branchName string
-	}
-	tests := []struct {
-		name string
-		args args
-		want *model.BranchDeleteStatus
-	}{
-		{name: "Git branch deletion test case", args: struct {
-			repo       *git.Repository
-			branchName string
-		}{repo: r, branchName: "test"}, want: &model.BranchDeleteStatus{Status: "BRANCH_DELETE_SUCCESS"}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.DeleteBranchInterface
-			testObj = git2.DeleteBranchInputs{
-				Repo:       tt.args.repo,
-				BranchName: tt.args.branchName,
-			}
-
-			git2.NewAddBranch(r, "test", false, nil).AddBranch()
-
-			got := testObj.DeleteBranch()
-			assert.Equal(t, tt.want, got)
-		})
-	}
-}
diff --git a/tests/git_branch_test.go b/tests/git_branch_test.go
deleted file mode 100644
index 748d2a8..0000000
--- a/tests/git_branch_test.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestGetBranchList(t *testing.T) {
-	b := make(chan git2.Branch)
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		branchChan chan git2.Branch
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git branch list test case", args: struct {
-			repo       *git.Repository
-			branchChan chan git2.Branch
-		}{repo: r, branchChan: b}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.BranchListInterface
-			testObj = git2.BranchListInputs{
-				Repo: tt.args.repo,
-			}
-			go testObj.GetBranchList(tt.args.branchChan)
-			branchList := <-tt.args.branchChan
-
-			cBranch := branchList.CurrentBranch
-			aBranch := branchList.AllBranchList
-			bList := branchList.BranchList
-
-			assert.NotZero(t, len(cBranch))
-			assert.NotZero(t, len(aBranch))
-			assert.NotZero(t, len(bList))
-		})
-	}
-}
diff --git a/tests/git_changed_files_test.go b/tests/git_changed_files_test.go
index 0bd4e0f..c64930e 100644
--- a/tests/git_changed_files_test.go
+++ b/tests/git_changed_files_test.go
@@ -13,7 +13,7 @@ import (
 )
 
 func TestChangedFiles(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	repoPath := r.Workdir()
 
 	mockFile := "mockFile.txt"
diff --git a/tests/git_commit_changes_test.go b/tests/git_commit_changes_test.go
deleted file mode 100644
index 8c71949..0000000
--- a/tests/git_commit_changes_test.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package tests
-
-import (
-	"fmt"
-	git2go "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"io/ioutil"
-	"testing"
-)
-
-func TestCommitChanges(t *testing.T) {
-	r, _ := git2go.OpenRepository(TestRepo)
-	repoPath := r.Workdir()
-
-	sampleFile := "untracked.txt"
-	err := ioutil.WriteFile(repoPath+"/"+sampleFile, []byte{byte(63)}, 0755)
-
-	var stageAllObjects git2.StageAllInterface
-	stageAllObjects = git2.StageAllStruct{Repo: r}
-
-	fmt.Println(err)
-	fmt.Println(stageAllObjects.StageAllItems())
-
-	type args struct {
-		repo          *git2go.Repository
-		commitMessage string
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{name: "Git commit changes test case", args: struct {
-			repo          *git2go.Repository
-			commitMessage string
-		}{repo: r, commitMessage: "Test commit"}, want: "COMMIT_DONE"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.CommitInterface
-			testObj = git2.CommitStruct{
-				Repo:          tt.args.repo,
-				CommitMessage: tt.args.commitMessage,
-				RepoPath:      repoPath,
-			}
-
-			got := testObj.CommitChanges()
-			assert.Equal(t, tt.want, got)
-		})
-	}
-}
diff --git a/tests/git_commit_compare_test.go b/tests/git_commit_compare_test.go
deleted file mode 100644
index 648b6ec..0000000
--- a/tests/git_commit_compare_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestCompareCommit(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	sampleCommits := git2.CommitLogStruct{
-		Repo:            r,
-		ReferenceCommit: "",
-	}.CommitLogs()
-
-	type args struct {
-		repo                *git.Repository
-		baseCommitString    string
-		compareCommitString string
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit compare test case", args: struct {
-			repo                *git.Repository
-			baseCommitString    string
-			compareCommitString string
-		}{repo: r, baseCommitString: *sampleCommits.Commits[1].Hash, compareCommitString: *sampleCommits.Commits[2].Hash}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.CompareCommitInterface
-			testObj = git2.CompareCommitStruct{
-				Repo:                tt.args.repo,
-				BaseCommitString:    tt.args.baseCommitString,
-				CompareCommitString: tt.args.compareCommitString,
-			}
-
-			got := testObj.CompareCommit()
-
-			assert.NotZero(t, len(got))
-		})
-	}
-}
diff --git a/tests/git_commit_files_test.go b/tests/git_commit_files_test.go
deleted file mode 100644
index ea22e0a..0000000
--- a/tests/git_commit_files_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestCommitFileList(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	sampleCommits := git2.CommitLogStruct{
-		Repo:            r,
-		ReferenceCommit: "",
-	}.CommitLogs()
-
-	type args struct {
-		repo       *git.Repository
-		commitHash string
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit file list test case", args: struct {
-			repo       *git.Repository
-			commitHash string
-		}{repo: r, commitHash: *sampleCommits.Commits[1].Hash}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObject git2.CommitFileListInterface
-			testObject = git2.CommitFileListStruct{
-				Repo:       tt.args.repo,
-				CommitHash: tt.args.commitHash,
-			}
-
-			got := testObject.CommitFileList()
-
-			assert.NotZero(t, len(got))
-		})
-	}
-}
diff --git a/tests/git_commit_log_search_test.go b/tests/git_commit_log_search_test.go
deleted file mode 100644
index 864d5b4..0000000
--- a/tests/git_commit_log_search_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestSearchCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	sampleCommits := git2.CommitLogStruct{
-		Repo:            r,
-		ReferenceCommit: "",
-	}.CommitLogs()
-	hash := *sampleCommits.Commits[0].Hash
-
-	type args struct {
-		repo       *git.Repository
-		searchType string
-		searchKey  string
-	}
-
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit log search test case", args: struct {
-			repo       *git.Repository
-			searchType string
-			searchKey  string
-		}{repo: r, searchType: "hash", searchKey: hash}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.SearchCommitInterface
-			testObj = git2.SearchCommitStruct{
-				Repo:       tt.args.repo,
-				SearchType: tt.args.searchType,
-				SearchKey:  tt.args.searchKey,
-			}
-
-			got := testObj.SearchCommitLogs()
-
-			assert.NotZero(t, len(got))
-		})
-	}
-}
diff --git a/tests/git_commit_logs_test.go b/tests/git_commit_logs_test.go
deleted file mode 100644
index f946a43..0000000
--- a/tests/git_commit_logs_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	assert2 "github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo      *git.Repository
-		skipCount int
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git commit logs test case", args: struct {
-			repo      *git.Repository
-			skipCount int
-		}{repo: r, skipCount: 0}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			assert := assert2.New(t)
-
-			var testObj git2.CommitLogInterface
-			testObj = git2.CommitLogStruct{
-				Repo:            tt.args.repo,
-				ReferenceCommit: "",
-			}
-
-			cLogs := testObj.CommitLogs()
-			gotTotal := *cLogs.TotalCommits
-
-			assert.NotZero(int(gotTotal))
-		})
-	}
-}
diff --git a/tests/git_ls_files_test.go b/tests/git_ls_files_test.go
index 8d2c175..c20937f 100644
--- a/tests/git_ls_files_test.go
+++ b/tests/git_ls_files_test.go
@@ -4,12 +4,13 @@ import (
 	"github.com/libgit2/git2go/v31"
 	git2 "github.com/neel1996/gitconvex/git"
 	"github.com/stretchr/testify/assert"
+	"os"
 	"testing"
 )
 
 func TestListFiles(t *testing.T) {
 	lsFileChan := make(chan *git2.LsFileInfo)
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 	repoPath := r.Workdir()
 
 	type args struct {
diff --git a/tests/git_remote_add_test.go b/tests/git_remote_add_test.go
deleted file mode 100644
index 8b9a37f..0000000
--- a/tests/git_remote_add_test.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestAddRemote(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		remoteName string
-		remoteURL  string
-	}
-	tests := []struct {
-		name string
-		args args
-		want string
-	}{
-		{name: "Git remote add test case", args: struct {
-			repo       *git.Repository
-			remoteName string
-			remoteURL  string
-		}{repo: r, remoteName: "test_remote", remoteURL: "https://github.com/neel1996/starfleet.git"}, want: "REMOTE_ADD_SUCCESS"},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.AddRemoteInterface
-			testObj = git2.AddRemoteStruct{
-				Repo:       tt.args.repo,
-				RemoteName: tt.args.remoteName,
-				RemoteURL:  tt.args.remoteURL,
-			}
-			got := testObj.AddRemote()
-
-			assert.Equal(t, tt.want, got.Status)
-
-			obj := git2.DeleteRemoteStruct{
-				Repo:       r,
-				RemoteName: tt.args.remoteName,
-			}
-			obj.DeleteRemote()
-		})
-	}
-}
diff --git a/tests/git_remote_allremotedata_test.go b/tests/git_remote_allremotedata_test.go
deleted file mode 100644
index 7f23fad..0000000
--- a/tests/git_remote_allremotedata_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	assert2 "github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestRemoteDataStruct_GetAllRemotes(t *testing.T) {
-	type fields struct {
-		Repo      *git.Repository
-		RemoteURL string
-	}
-
-	r, _ := git.OpenRepository(TestRepo)
-
-	tests := []struct {
-		name   string
-		fields fields
-	}{
-		{name: "Test for all remote data", fields: struct {
-			Repo      *git.Repository
-			RemoteURL string
-		}{Repo: r, RemoteURL: ""}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			res := git2.RemoteDataStruct{
-				Repo:      tt.fields.Repo,
-				RemoteURL: tt.fields.RemoteURL,
-			}
-			got := res.GetAllRemotes()
-
-			assert2.NotZero(t, got)
-		})
-	}
-}
diff --git a/tests/git_remote_data_test.go b/tests/git_remote_data_test.go
deleted file mode 100644
index 47e5669..0000000
--- a/tests/git_remote_data_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	assert2 "github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestRemoteData(t *testing.T) {
-	remoteChan := make(chan git2.RemoteDataModel)
-	r, _ := git.OpenRepository(TestRepo)
-
-	type args struct {
-		repo       *git.Repository
-		remoteChan chan git2.RemoteDataModel
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git remote data test case", args: struct {
-			repo       *git.Repository
-			remoteChan chan git2.RemoteDataModel
-		}{repo: r, remoteChan: remoteChan}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			assert := assert2.New(t)
-			var testObj git2.RemoteDataInterface
-			testObj = git2.RemoteDataStruct{
-				Repo: tt.args.repo,
-			}
-			go testObj.RemoteData(tt.args.remoteChan)
-			remoteData := <-remoteChan
-
-			rHost := remoteData.RemoteHost
-			rURL := remoteData.RemoteURL
-
-			assert.Contains(*rURL[0], "github")
-			assert.Equal(*rHost, "github")
-		})
-	}
-}
diff --git a/tests/git_remote_delete_test.go b/tests/git_remote_delete_test.go
deleted file mode 100644
index c0228cc..0000000
--- a/tests/git_remote_delete_test.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/neel1996/gitconvex/graph/model"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestDeleteRemoteStruct_DeleteRemote(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	testRemoteName := "test_remote"
-	var testObj git2.AddRemoteInterface
-	testObj = git2.AddRemoteStruct{
-		Repo:       r,
-		RemoteName: testRemoteName,
-		RemoteURL:  "git@github.com:neel1996/gitconvex-server.git",
-	}
-	_ = testObj.AddRemote()
-
-	type fields struct {
-		Repo       git.Repository
-		RemoteName string
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   *model.RemoteMutationResult
-	}{
-		{name: "Test for remote deletion", fields: struct {
-			Repo       git.Repository
-			RemoteName string
-		}{Repo: *r, RemoteName: testRemoteName}, want: &model.RemoteMutationResult{Status: global.RemoteDeleteSuccess}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			d := &git2.DeleteRemoteStruct{
-				Repo:       &tt.fields.Repo,
-				RemoteName: tt.fields.RemoteName,
-			}
-			got := d.DeleteRemote()
-
-			assert.Equal(t, tt.want.Status, got.Status)
-		})
-	}
-}
diff --git a/tests/git_remote_edit_test.go b/tests/git_remote_edit_test.go
deleted file mode 100644
index 4b169e4..0000000
--- a/tests/git_remote_edit_test.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/neel1996/gitconvex/global"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestRemoteEditStruct_EditRemoteUrl(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	type fields struct {
-		Repo       *git.Repository
-		RemoteName string
-		RemoteUrl  string
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   string
-	}{
-		{name: "Test edit remote api", fields: struct {
-			Repo       *git.Repository
-			RemoteName string
-			RemoteUrl  string
-		}{Repo: r, RemoteName: "origin", RemoteUrl: "git@github.com:neel1996/gitconvex-server.git"}, want: global.RemoteEditSuccess},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			e := &git2.RemoteEditStruct{
-				Repo:       tt.fields.Repo,
-				RemoteName: tt.fields.RemoteName,
-				RemoteUrl:  tt.fields.RemoteUrl,
-			}
-			got := e.EditRemoteUrl()
-
-			assert.Equal(t, tt.want, got.Status)
-		})
-	}
-}
diff --git a/tests/git_resetall_items_test.go b/tests/git_resetall_items_test.go
index 65d6b1a..95a5ef6 100644
--- a/tests/git_resetall_items_test.go
+++ b/tests/git_resetall_items_test.go
@@ -10,7 +10,7 @@ import (
 )
 
 func TestResetAllItems(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
+	r, _ := git.OpenRepository(os.Getenv("GITCONVEX_TEST_REPO"))
 
 	mockFile := "untracked.txt"
 	_ = ioutil.WriteFile(mockFile, []byte{byte(63)}, 0755)
diff --git a/tests/git_total_commits_test.go b/tests/git_total_commits_test.go
deleted file mode 100644
index 17ce7f0..0000000
--- a/tests/git_total_commits_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package tests
-
-import (
-	git "github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestTotalCommitLogs(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-
-	logChan := make(chan git2.AllCommitData)
-
-	type args struct {
-		repo       *git.Repository
-		commitChan chan git2.AllCommitData
-	}
-	tests := []struct {
-		name string
-		args args
-	}{
-		{name: "Git logs test case", args: struct {
-			repo       *git.Repository
-			commitChan chan git2.AllCommitData
-		}{repo: r, commitChan: logChan}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			zeroValue := float64(0)
-
-			var testObj git2.AllCommitInterface
-			testObj = git2.AllCommitStruct{Repo: tt.args.repo}
-			go testObj.AllCommits(tt.args.commitChan)
-			commits := <-logChan
-			commitLength := commits.TotalCommits
-
-			assert.Greater(t, commitLength, zeroValue)
-		})
-	}
-}
diff --git a/tests/git_unpushed_commits_test.go b/tests/git_unpushed_commits_test.go
deleted file mode 100644
index a756995..0000000
--- a/tests/git_unpushed_commits_test.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package tests
-
-import (
-	"github.com/libgit2/git2go/v31"
-	git2 "github.com/neel1996/gitconvex/git"
-	"io/ioutil"
-	"strings"
-	"testing"
-)
-
-func TestUnPushedCommits(t *testing.T) {
-	r, _ := git.OpenRepository(TestRepo)
-	repoPath := r.Workdir()
-
-	untrackedResult := "untracked.txt"
-
-	_ = ioutil.WriteFile(repoPath+untrackedResult, []byte{byte(63)}, 0755)
-
-	var stageObject git2.StageItemInterface
-	var commitObject git2.CommitInterface
-
-	stageObject = git2.StageItemStruct{
-		Repo:     r,
-		FileItem: untrackedResult,
-	}
-
-	commitObject = git2.CommitStruct{
-		Repo:          r,
-		CommitMessage: "Test Commit",
-	}
-
-	stageObject.StageItem()
-	commitObject.CommitChanges()
-
-	type args struct {
-		repo      *git.Repository
-		remoteRef string
-	}
-	tests := []struct {
-		name string
-		args args
-		want []*string
-	}{
-		{name: "Git unpushed commit list test case", args: struct {
-			repo      *git.Repository
-			remoteRef string
-		}{repo: r, remoteRef: "origin/master"}, want: []*string{}},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			var testObj git2.UnPushedCommitInterface
-			testObj = git2.UnPushedCommitStruct{
-				Repo:      tt.args.repo,
-				RemoteRef: tt.args.remoteRef,
-			}
-			if got := testObj.UnPushedCommits(); !strings.Contains(*got.GitCommits[0].CommitMessage, "Test Commit") {
-				t.Errorf("UnPushedCommits() = %v, want %v", got, tt.want)
-			}
-		})
-	}
-}
diff --git a/tests/update_repo_name_test.go b/tests/update_repo_name_test.go
deleted file mode 100644
index 9beb6a9..0000000
--- a/tests/update_repo_name_test.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package tests
-
-import (
-	"github.com/neel1996/gitconvex/api"
-	"github.com/neel1996/gitconvex/utils"
-	"github.com/stretchr/testify/assert"
-	"testing"
-)
-
-func TestUpdateRepoName(t *testing.T) {
-	var testObj api.AddRepoInterface
-	testObj = api.AddRepoInputs{
-		RepoName: "test", RepoPath: "..", CloneSwitch: false, RepoURL: "", InitSwitch: false, AuthOption: "", UserName: "", Password: "",
-	}
-	_ = utils.EnvConfigFileGenerator()
-	testRepoId := testObj.AddRepo().RepoID
-
-	type args struct {
-		repoId   string
-		repoName string
-	}
-	tests := []struct {
-		name    string
-		args    args
-		want    string
-		wantErr bool
-	}{
-		{name: "test script for rename repo API", args: struct {
-			repoId   string
-			repoName string
-		}{repoId: testRepoId, repoName: "NewTest"}, want: "Repo name updated successfully", wantErr: false},
-	}
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			got, err := api.UpdateRepoName(tt.args.repoId, tt.args.repoName)
-
-			assert.Nil(t, err)
-			assert.Equal(t, tt.want, got)
-		})
-	}
-}
diff --git a/utils/array_generator.go b/utils/array_generator.go
new file mode 100644
index 0000000..0706ee0
--- /dev/null
+++ b/utils/array_generator.go
@@ -0,0 +1,21 @@
+package utils
+
+func GeneratePointerArrayFrom(array []string) []*string {
+	var pointerArray []*string
+
+	for _, element := range array {
+		pointerArray = append(pointerArray, &element)
+	}
+
+	return pointerArray
+}
+
+func GenerateNonPointerArrayFrom(array []*string) []string {
+	var pointerArray []string
+
+	for _, element := range array {
+		pointerArray = append(pointerArray, *element)
+	}
+
+	return pointerArray
+}
diff --git a/utils/default_dir_setup.go b/utils/default_dir_setup.go
index 45a0747..bbba1d2 100644
--- a/utils/default_dir_setup.go
+++ b/utils/default_dir_setup.go
@@ -1,7 +1,6 @@
 package utils
 
 import (
-	"flag"
 	"github.com/neel1996/gitconvex/global"
 	"go/types"
 	"os"
@@ -10,19 +9,10 @@ import (
 )
 
 func DefaultDirSetup() (string, error) {
-	var baseDirPath *string
-	baseDirFlag := flag.Lookup("basedir")
+	baseDirPath := global.GetDefaultDirectory()
 
-	if baseDirFlag == nil {
-		baseDirPath = flag.String("basedir", "/usr/local/gitconvex", "Default gitconvex directory path for Linux and MacOS")
-		flag.Parse()
-	} else {
-		flagPath := baseDirFlag.Value.String()
-		baseDirPath = &flagPath
-	}
-
-	if baseDirPath == nil {
-		return "", types.Error{Msg: "Unable to parse basedir flag"}
+	if baseDirPath == "" {
+		return "", types.Error{Msg: "Default directory path value is empty"}
 	}
 
 	if runtime.GOOS == "windows" {
@@ -38,15 +28,15 @@ func DefaultDirSetup() (string, error) {
 		return execPath, nil
 	}
 
-	_, statErr := os.Stat(*baseDirPath)
+	_, statErr := os.Stat(baseDirPath)
 	if statErr != nil {
-		err := os.Mkdir(*baseDirPath, 0755)
+		err := os.Mkdir(baseDirPath, 0644)
 		if err != nil {
 			logger.Log(err.Error(), global.StatusError)
 			return "", err
 		}
 	} else {
-		return *baseDirPath, nil
+		return baseDirPath, nil
 	}
 
 	return "", nil
diff --git a/utils/env_file_handler.go b/utils/env_file_handler.go
index 7713b3c..0a8b7d9 100644
--- a/utils/env_file_handler.go
+++ b/utils/env_file_handler.go
@@ -42,6 +42,7 @@ func EnvConfigValidator() error {
 func EnvConfigFileReader() *EnvConfig {
 	cwd, cwdErr := DefaultDirSetup()
 	if cwdErr != nil {
+		logger.Log(cwdErr.Error(), global.StatusError)
 		return nil
 	}
 
diff --git a/validator/branch_validator.go b/validator/branch_validator.go
new file mode 100644
index 0000000..c0be454
--- /dev/null
+++ b/validator/branch_validator.go
@@ -0,0 +1,22 @@
+package validator
+
+type branchValidator struct {
+}
+
+func (v branchValidator) ValidateWithFields(branchNames ...string) error {
+	if len(branchNames) == 0 {
+		return EmptyBranchName
+	}
+
+	for _, branchName := range branchNames {
+		if branchName == "" {
+			return EmptyBranchName
+		}
+	}
+
+	return nil
+}
+
+func NewBranchValidator() ValidatorWithStringFields {
+	return branchValidator{}
+}
diff --git a/validator/branch_validator_test.go b/validator/branch_validator_test.go
new file mode 100644
index 0000000..cfe2be2
--- /dev/null
+++ b/validator/branch_validator_test.go
@@ -0,0 +1,45 @@
+package validator
+
+import (
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type BranchValidatorTestSuite struct {
+	suite.Suite
+	branchValidator ValidatorWithStringFields
+}
+
+func TestBranchValidatorTestSuite(t *testing.T) {
+	suite.Run(t, new(BranchValidatorTestSuite))
+}
+
+func (suite *BranchValidatorTestSuite) SetupTest() {
+	suite.branchValidator = NewBranchValidator()
+}
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenPassedBranchIsValid_ShouldReturnNil() {
+	err := suite.branchValidator.ValidateWithFields("test_1")
+
+	suite.Nil(err)
+}
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenPassedBranchesAreValid_ShouldReturnNil() {
+	err := suite.branchValidator.ValidateWithFields("test_1", "test_2")
+
+	suite.Nil(err)
+}
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenNoBranchesArePassed_ShouldReturnEmptyBranchError() {
+	err := suite.branchValidator.ValidateWithFields()
+
+	suite.NotNil(err)
+	suite.Equal(EmptyBranchName, err)
+}
+
+func (suite *BranchValidatorTestSuite) TestValidate_WhenEmptyStringIsPassed_ShouldReturnEmptyBranchError() {
+	err := suite.branchValidator.ValidateWithFields("")
+
+	suite.NotNil(err)
+	suite.Equal(EmptyBranchName, err)
+}
diff --git a/validator/mocks/mock_validator.go b/validator/mocks/mock_validator.go
new file mode 100644
index 0000000..d4337cf
--- /dev/null
+++ b/validator/mocks/mock_validator.go
@@ -0,0 +1,89 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: validator/validator.go
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	reflect "reflect"
+
+	gomock "github.com/golang/mock/gomock"
+)
+
+// MockValidator is a mock of Validator interface.
+type MockValidator struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidatorMockRecorder
+}
+
+// MockValidatorMockRecorder is the mock recorder for MockValidator.
+type MockValidatorMockRecorder struct {
+	mock *MockValidator
+}
+
+// NewMockValidator creates a new mock instance.
+func NewMockValidator(ctrl *gomock.Controller) *MockValidator {
+	mock := &MockValidator{ctrl: ctrl}
+	mock.recorder = &MockValidatorMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidator) EXPECT() *MockValidatorMockRecorder {
+	return m.recorder
+}
+
+// Validate mocks base method.
+func (m *MockValidator) Validate(arg0 interface{}) error {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "Validate", arg0)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// Validate indicates an expected call of Validate.
+func (mr *MockValidatorMockRecorder) Validate(arg0 interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Validate", reflect.TypeOf((*MockValidator)(nil).Validate), arg0)
+}
+
+// MockValidatorWithStringFields is a mock of ValidatorWithStringFields interface.
+type MockValidatorWithStringFields struct {
+	ctrl     *gomock.Controller
+	recorder *MockValidatorWithStringFieldsMockRecorder
+}
+
+// MockValidatorWithStringFieldsMockRecorder is the mock recorder for MockValidatorWithStringFields.
+type MockValidatorWithStringFieldsMockRecorder struct {
+	mock *MockValidatorWithStringFields
+}
+
+// NewMockValidatorWithStringFields creates a new mock instance.
+func NewMockValidatorWithStringFields(ctrl *gomock.Controller) *MockValidatorWithStringFields {
+	mock := &MockValidatorWithStringFields{ctrl: ctrl}
+	mock.recorder = &MockValidatorWithStringFieldsMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockValidatorWithStringFields) EXPECT() *MockValidatorWithStringFieldsMockRecorder {
+	return m.recorder
+}
+
+// ValidateWithFields mocks base method.
+func (m *MockValidatorWithStringFields) ValidateWithFields(fields ...string) error {
+	m.ctrl.T.Helper()
+	varargs := []interface{}{}
+	for _, a := range fields {
+		varargs = append(varargs, a)
+	}
+	ret := m.ctrl.Call(m, "ValidateWithFields", varargs...)
+	ret0, _ := ret[0].(error)
+	return ret0
+}
+
+// ValidateWithFields indicates an expected call of ValidateWithFields.
+func (mr *MockValidatorWithStringFieldsMockRecorder) ValidateWithFields(fields ...interface{}) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateWithFields", reflect.TypeOf((*MockValidatorWithStringFields)(nil).ValidateWithFields), fields...)
+}
diff --git a/validator/repo_validator.go b/validator/repo_validator.go
new file mode 100644
index 0000000..371648c
--- /dev/null
+++ b/validator/repo_validator.go
@@ -0,0 +1,21 @@
+package validator
+
+import "github.com/neel1996/gitconvex/git/middleware"
+
+type repoValidator struct {
+}
+
+func (v repoValidator) Validate(r interface{}) error {
+	if r == nil {
+		return NilRepoError
+	}
+
+	if repo, ok := r.(middleware.Repository); !ok || repo == nil {
+		return NilRepoError
+	}
+	return nil
+}
+
+func NewRepoValidator() Validator {
+	return repoValidator{}
+}
diff --git a/validator/repo_validator_test.go b/validator/repo_validator_test.go
new file mode 100644
index 0000000..094e02a
--- /dev/null
+++ b/validator/repo_validator_test.go
@@ -0,0 +1,53 @@
+package validator
+
+import (
+	"github.com/golang/mock/gomock"
+	"github.com/neel1996/gitconvex/mocks"
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type RepoValidatorTestSuite struct {
+	suite.Suite
+	mockController *gomock.Controller
+	mockRepo       *mocks.MockRepository
+	repoValidator  Validator
+}
+
+func TestRepoValidatorTestSuite(t *testing.T) {
+	suite.Run(t, new(RepoValidatorTestSuite))
+}
+
+func (suite *RepoValidatorTestSuite) SetupTest() {
+	suite.mockController = gomock.NewController(suite.T())
+	suite.mockRepo = mocks.NewMockRepository(suite.mockController)
+	suite.repoValidator = NewRepoValidator()
+}
+
+func (suite *RepoValidatorTestSuite) TearDownTest() {
+	suite.mockController.Finish()
+}
+
+func (suite *RepoValidatorTestSuite) TestValidate_WhenRepoIsNotNil_ShouldReturnNil() {
+	err := suite.repoValidator.Validate(suite.mockRepo)
+
+	suite.Nil(err)
+}
+
+func (suite *RepoValidatorTestSuite) TestValidate_WhenRepoIsNil_ShouldReturnRepoNilError() {
+	suite.repoValidator = NewRepoValidator()
+
+	err := suite.repoValidator.Validate(nil)
+
+	suite.NotNil(err)
+	suite.Equal(NilRepoError, err)
+}
+
+func (suite *RepoValidatorTestSuite) TestValidate_WhenWrongTypeOfInputIsPassed_ShouldReturnRepoNilError() {
+	suite.repoValidator = NewRepoValidator()
+
+	err := suite.repoValidator.Validate("nil")
+
+	suite.NotNil(err)
+	suite.Equal(NilRepoError, err)
+}
diff --git a/validator/validation_errors.go b/validator/validation_errors.go
new file mode 100644
index 0000000..e8493ac
--- /dev/null
+++ b/validator/validation_errors.go
@@ -0,0 +1,16 @@
+package validator
+
+type Error struct {
+	error
+	ErrorCode   string
+	ErrorString string
+}
+
+var (
+	NilRepoError    = Error{ErrorCode: "REPO_NIL_ERROR", ErrorString: "Repo is nil"}
+	EmptyBranchName = Error{ErrorCode: "EMPTY_BRANCH_NAME", ErrorString: "Branch name is empty"}
+)
+
+func (e Error) Error() string {
+	return e.ErrorString
+}
diff --git a/validator/validation_errors_test.go b/validator/validation_errors_test.go
new file mode 100644
index 0000000..096e04f
--- /dev/null
+++ b/validator/validation_errors_test.go
@@ -0,0 +1,21 @@
+package validator
+
+import (
+	"github.com/stretchr/testify/suite"
+	"testing"
+)
+
+type ValidationErrorTestSuite struct {
+	suite.Suite
+	validationError Error
+}
+
+func TestValidationErrorTestSuite(t *testing.T) {
+	suite.Run(t, new(ValidationErrorTestSuite))
+}
+
+func (suite *ValidationErrorTestSuite) TestError_ShouldReturnErrorString() {
+	suite.validationError = NilRepoError
+
+	suite.Equal("Repo is nil", suite.validationError.Error())
+}
diff --git a/validator/validator.go b/validator/validator.go
new file mode 100644
index 0000000..1d38fdb
--- /dev/null
+++ b/validator/validator.go
@@ -0,0 +1,9 @@
+package validator
+
+type Validator interface {
+	Validate(interface{}) error
+}
+
+type ValidatorWithStringFields interface {
+	ValidateWithFields(fields ...string) error
+}
