255

For some reason, I only have one repository to use.
But I have multiple projects including java projects, PHP scripts and Android apps projects.

Now my problem is, I have to put them to different sub-folders inside the repository
I use different IDEs, You know, each IDE can have a workspace of itself.

Is there a simple way (say, by design and not by opinion) to solve the problem?

Aanshumaan Shrijai
  • 109
  • 1
  • 1
  • 11
Stony
  • 3,541
  • 3
  • 17
  • 23
  • 1
    A possible solution could be http://stackoverflow.com/questions/5514739/best-practice-for-git-repositories-with-multiple-projects-in-traditional-n-tier?rq=1 or http://stackoverflow.com/a/7931825/828197 – Ragnarokkr Feb 04 '13 at 02:32
  • 3
    You're not alone. I have similar case with my repos that I use for learning purposes (example: https://github.com/hopbit/java-sandbox). I don't want to create new repo to try examples for every new book/tutorial I start to read... – Łukasz Siwiński Feb 05 '13 at 10:09
  • 1
    One reason you'd want to do this is if you've got one project that is product code which you deploy to runtime environments like test or production. The second project is an application which system tests (BDD for example) the first project. There is close a relationship between these two projects and now you can maintain/refer to the entirety using one repository url. – Lance Kind Apr 12 '17 at 16:17
  • Summary as below **"Git has no idea whether these are parts of the same or different projects"** – Ahmed Nabil Feb 13 '19 at 22:51

3 Answers3

244

While most people will tell you to just use multiple repositories, I feel it's worth mentioning there are other solutions.

Solution 1

A single repository can contain multiple independent branches, called orphan branches. Orphan branches are completely separate from each other; they do not share histories.

git checkout --orphan BRANCHNAME

This creates a new branch, unrelated to your current branch. Each project should be in its own orphaned branch.

Now for whatever reason, git needs a bit of cleanup after an orphan checkout.

rm .git/index
rm -r *

Make sure everything is committed before deleting

Once the orphan branch is clean, you can use it normally.

Solution 2

Avoid all the hassle of orphan branches. Create two independent repositories, and push them to the same remote. Just use different branch names for each repo.

# repo 1
git push origin master:master-1

# repo 2
git push origin master:master-2
Jacob Groundwater
  • 6,581
  • 1
  • 28
  • 42
  • 3
    Thanks a lot, that should be able to solve my problem. Actually, the two solutions use branchs to hold different projects. – Stony Feb 19 '13 at 06:50
  • 8
    I'm not sure I understand solution 2. Are you saying you commit all the .git files into a master git repo? What's different between using multiple orphaned branches vs using multiple branches? – Nate Mar 12 '14 at 18:53
  • 24
    @Nate What he is saying is this: make two separate _local_ repositories, then push them both to the same _remote_ repository on GitHub. – The Guy with The Hat Dec 12 '14 at 18:40
  • 2
    Thanks @TheGuywithTheElfHat. Now that I look at it again (9 months later) it seems clear to me. Solution 2 is still creating orphaned branches but I can see how this method is easier to deal with. – Nate Dec 12 '14 at 20:16
  • Like solutions 2. Easy and fast. Git should be used as repo, but it shall also permit some tweaks. – WesternGun Aug 09 '16 at 07:55
  • Wish I'd known about orphan branches a month ago! I had to implement a complex branching solution for a customization team to track changes to templates to match client demands. The customization branches will never be merged back to master. – OrionRogue Aug 10 '16 at 16:27
  • 1
    The difference between the two solutions is about the road that lead you here. If you don't already have two separate repos, so you go with solution 1. If you've already got two separate repos, and decide you want them organized in one repo, then solution 2 fits the bill. – Lance Kind Apr 12 '17 at 16:22
  • 34
    Solution 2 needs more explanation – eC Droid Nov 29 '17 at 12:13
  • With solution 2, after a while if a new developer comes in and will only work on project 2, can they clone without getting all the stuff in project 1? Asking because a new repo was recently set up, with the Java API on one branch, and the frontend Angular app in another, but nobody will be working on both. Wondering if I should try this solution or just split to 2 repos. – redOctober13 Jun 22 '18 at 15:13
  • @redOctober13 git supports the ability to clone just one of the branches from a master repo: https://stackoverflow.com/questions/1778088/how-do-i-clone-a-single-branch-in-git - I think this is what you would want for your two developers working on the same overall project... – moilejter Sep 25 '18 at 22:44
  • for the second solution we need to create a 3rd repo that it gonna be the master? – Bogdan Mar 30 '21 at 08:06
  • I think **solution 1** is part of the best way to do so. Its not by-design but it's okay. This is the way to have separate trees, but says nothing on how to organize them. In **solution 3** they explain how to organize branches in folders using "/" character. On the other hand, **solution 2** requires multiple remote repositories and for that, the by-design option would be **git submodules**. – DuniC Nov 23 '21 at 20:00
  • @JacobGroundwater , with the solution 1 : do I have to place each projects folder inside the cloned repo ? – pheromix Dec 03 '21 at 08:00
26

Solution 3

This is for using a single directory for multiple projects. I use this technique for some closely related projects where I often need to pull changes from one project into another. It's similar to the orphaned branches idea but the branches don't need to be orphaned. Simply start all the projects from the same empty directory state.

Start all projects from one committed empty directory

Don't expect wonders from this solution. As I see it, you are always going to have annoyances with untracked files. Git doesn't really have a clue what to do with them and so if there are intermediate files generated by a compiler and ignored by your .gitignore file, it is likely that they will be left hanging some of the time if you try rapidly swapping between - for example - your software project and a PH.D thesis project.

However here is the plan. Start as you ought to start any git projects, by committing the empty repository, and then start all your projects from the same empty directory state. That way you are certain that the two lots of files are fairly independent. Also, give your branches a proper name and don't lazily just use "master". Your projects need to be separate so give them appropriate names.

Git commits (and hence tags and branches) basically store the state of a directory and its subdirectories and Git has no idea whether these are parts of the same or different projects so really there is no problem for git storing different projects in the same repository. The problem is then for you clearing up the untracked files from one project when using another, or separating the projects later.

Create an empty repository

cd some_empty_directory
git init
touch .gitignore
git add .gitignore
git commit -m empty
git tag EMPTY

Start your projects from empty.

Work on one project.

git branch software EMPTY
git checkout software
echo "array board[8,8] of piece" > chess.prog

git add chess.prog 
git commit -m "chess program"

Start another project

whenever you like.

git branch thesis EMPTY
git checkout thesis
echo "the meaning of meaning" > philosophy_doctorate.txt
git add philosophy_doctorate.txt 
git commit -m "Ph.D"

Switch back and forth

Go back and forwards between projects whenever you like. This example goes back to the chess software project.

git checkout software
echo "while not end_of_game do make_move()" >> chess.prog
git add chess.prog 
git commit -m "improved chess program"

Untracked files are annoying

You will however be annoyed by untracked files when swapping between projects/branches.

touch untracked_software_file.prog
git checkout thesis 
ls
    philosophy_doctorate.txt  untracked_software_file.prog

It's not an insurmountable problem

Sort of by definition, git doesn't really know what to do with untracked files and it's up to you to deal with them. You can stop untracked files from being carried around from one branch to another as follows.

git checkout EMPTY 
ls
    untracked_software_file.prog
rm -r *
    (directory is now really empty, apart from the repository stuff!)
git checkout thesis
ls
    philosophy_doctorate.txt

By ensuring that the directory was empty before checking out our new project we made sure there were no hanging untracked files from another project.

A refinement

$ GIT_AUTHOR_DATE='2001-01-01:T01:01:01' GIT_COMMITTER_DATE='2001-01-01T01:01:01' git commit -m empty

If the same dates are specified whenever committing an empty repository, then independently created empty repository commits can have the same SHA1 code. This allows two repositories to be created independently and then merged together into a single tree with a common root in one repository later.

Example

# Create thesis repository. 
# Merge existing chess repository branch into it

mkdir single_repo_for_thesis_and_chess
cd single_repo_for_thesis_and_chess
git init
touch .gitignore
git add .gitignore
GIT_AUTHOR_DATE='2001-01-01:T01:01:01' GIT_COMMITTER_DATE='2001-01-01:T01:01:01' git commit -m empty
git tag EMPTY
echo "the meaning of meaning" > thesis.txt
git add thesis.txt
git commit -m "Wrote my PH.D"
git branch -m master thesis

# It's as simple as this ...
git remote add chess ../chessrepository/.git
git fetch chess chess:chess

Result

Diagram of merged repositories

Use subdirectories per project?

It may also help if you keep your projects in subdirectories where possible, e.g. instead of having files

chess.prog
philosophy_doctorate.txt 

have

chess/chess.prog
thesis/philosophy_doctorate.txt 

In this case your untracked software file will be chess/untracked_software_file.prog. When working in the thesis directory you should not be disturbed by untracked chess program files, and you may find occasions when you can work happily without deleting untracked files from other projects.

Also, if you want to remove untracked files from other projects, it will be quicker (and less prone to error) to dump an unwanted directory than to remove unwanted files by selecting each of them.

Branch names can include '/' characters

So you might want to name your branches something like

project1/master
project1/featureABC
project2/master
project2/featureXYZ
Ivan
  • 4,383
  • 36
  • 27
  • I think the key here is naming branches int folders using "/" character. Then to have separate branches you can do 2 things: 1) Have an actually empty common root commit with `git commit --allow-empty` -- improvement of solution 3--. 2) Have multiple root commits using `git checkout --orphan $project/$branch`. – DuniC Nov 23 '21 at 20:08
  • I have 2 folders for 2 different projects, but still untrack changes mixed . i have `.git` in root folder, and under it I have BE, FE folders, each one contains its own `.gitignore` file, what should I do to ignore the opposite files ?! thanks a lot – Adir Dayan Jun 19 '22 at 21:21
18

I would use git submodules.

have a look here Git repository in a Git repository

As per February2019, I would suggest Monorepos

Hitmands
  • 13,491
  • 4
  • 34
  • 69