Maintaining mulitple git repo for same Project
2022-08-27 . 2 min read
The Problem
Initializing git in the project dir, adding a .gitignore, adding remote origin and pushing to origin, we all have been doing this all the time but sometimes we might need to maintain 2 different Github repo and maybe we want to track and ignore different files as required. How can we do this? 🤔
Git is the most used version control system and it has been around for quite a while, so there must be a way to do this. After a while of researching on this, I found out that there is actually a way to do this.
Using Multiple Git Directories
So we all know, a hidden folder .git is created when we initialize git in a project directory and a .gitignore file lets us tell git not to track certain files. Now, what we can do is create a separate git dir to do the same thing as the existing one does with the command
git --git-dir=path_to_where_you_want --work-tree=path_to_your_project init
with this, we tell git to initialize yet another git directory wherever we want and also tell git the path to our project with the --work-tree option. You would normally want to initialize this separate dit directory in the same directory as where your project is. But up until now the custom git and the original git are both tracking the same changes. We might have some files which we do not want one of the gits to track so that certain things can be hidden from the public when we push to a remote repository. But there's only one gitignore, so how we separately track the changes?
Ignoring Changes Separately
If you have ever dissected the .git folder, you might have noticed that there's an info folder inside it that contains a exclude file. This file serves the same purpose as that of the .gitignore file at the root of our project and has the same syntax but the main difference is that unlike the .gitignore file the changes inside the git directory are not tracked and not pushed to the remote repo which is what we want. Just add the files inside this exclude file just as you would in the .gitignore file and VOILÀ now you tracking changes using 2 git dir. separately, ignoring separate files. Yippie🥳.... but wait, we still have to include this custom git directory in the gitignore file. Well, now our work is done.
Staging Changes, Commit and Push
Adding files to the staging area for committing and pushing is usually the next step. When we normally stage and commit changes, we don't pass any additional options to git other than what is strictly required. But since we have initiated a custom git dir, we have to explicitly tell git that we want the version control system in that specific directory. So, whenever we want to do this just add the options:
git --git-dir=path_to_where_you_want --work-tree=path_to_your_project init | add | commit
Automating with Bash
When using multiple different git dir for the same project, we find ourself adding and committing the same changes multiple times which can be boring, instead we can write a shell script to automate things for us. I made one with similar usage as git but does the work for all the git dir inside our project.
#! /bin/bash
GREEN=$(tput setaf 2)
RED=$(tput setaf 1)
NC=$(tput sgr0)
cmd=$1
function bold {
tput bold
echo -n "$@"
tput sgr0
}
case $cmd in
add)
if [ -z $2 ]; then
echo "${RED}$(bold Usage: cgit add file1 file2 ...)${NC}"
exit
fi
echo "${GREEN}$(bold ----Adding files----)${NC}"
git add ${@:2}
git --git-dir=./.gitPublic --work-tree=. add ${@:2}
exit 0
;;
status)
echo "${GREEN}$(bold ----Start of deployment git status----)${NC}"
git status
echo "${GREEN}$(bold ----End of deployment git status----)${NC}"
echo "${GREEN}$(bold ----Start of public git status----)${NC}"
git --git-dir=./.gitPublic --work-tree=. status
echo "${GREEN}$(bold ----End of public git status----)${NC}"
exit 0
;;
commit)
if [ $2 != '-m' ]; then
echo "${RED}$(bold Usage: cgit comit -m 'commit message')${NC}"
elif [ !$3 ]; then
echo "${RED}$(bold Usage: cgit comit -m 'commit message')${NC}"
else
git commit -m "$3"
git --git-dir=./.gitPublic --work-tree=. commit -m "$3"
fi
exit 0
;;
push)
echo "${GREEN}$(bold ----Pushing to deployment repo----)${NC}"
git push -u origin main
echo "${GREEN}$(bold ----Push to deployment repo finished----)${NC}"
echo "${GREEN}$(bold ----Push to public repo----)${NC}"
git --git-dir=./.gitPublic --work-tree=. push
echo "${GREEN}$(bold ----Pushing to public repo finished----)${NC}"
exit 0
;;
reset)
git reset
git --git-dir=./.gitPublic --work-tree=. reset
echo "${GREEN}$(bold ----Reset Done----)${NC}"
exit 0
;;
esac
So in the above script, we can see that the name of the custom git directory is .gitPublic which is in the root of the project directory and so the work-tree is a dot😯. We could also just make a script that accepts the names of the files to stage and a commit message and just do all the steps in just one cmd.
References and Resources
- The Internet (Especially Stackoverflow)
Hey I assume you finished reading, I would love to know your feedback or if found any error or mistake in this blog post, please do not hesitate to reach out to me.