Maintain git repo inside another git repo
Asked Answered
T

10

196

Here's what I'd like:

REPO-A
  /.git
  /otherFiles
  /REPO-B
    /.git
    /moreFiles

I want to be able to push all of REPO-A's contents to REMOTE-A and only REPO-B to REMOTE-B.

Possible?

Tit answered 11/1, 2011 at 15:53 Comment(1)
one of the simple and popular ideas below, just git ignore REPO_B: cd REPO-A && touch .gitignore && echo "./REPO-B" >> .gitignore.Rotten
M
178

It sounds like you want to use Git submodules.

Git addresses this issue using submodules. Submodules allow you to keep a Git repository as a subdirectory of another Git repository. This lets you clone another repository into your project and keep your commits separate.

Mauromaurois answered 11/1, 2011 at 16:5 Comment(4)
Not exactly: it won't push all content of repoA: only A plus a reference to B. But I don't criticize your answer, I was rushing writing pretty much the same when I re-read the OP's question ;)Hassan
This is pretty much the use case for submodules. REPO-A and REPO-B are treated as git repos in their own right, with their own commits, origins, history, etc.Cyanocobalamin
so if I am reading that right, can I independently check out a submodule-d repo entirely outside of the one I find it in? How would I take an already existing repo and reference it as a submodule in another project?Melodiemelodion
i wasn't looking for exactly the same solution as OP, and i reckon on average this is probably a more searched for answer to a similar question: "does placing git REPO-B within git REPO-A embed a reference or a full copy of git REPO-B?".Plumbic
M
99

I have always used symlinks to maintain two separate and distinct repos.

Melodiemelodion answered 11/1, 2011 at 16:38 Comment(9)
for how confusing git submodules and git sub-tree seem be, this is a valid answer.Safar
This is also very useful for assembling one application from multiple remote repositoriesDomenic
To maintain two separate and distinct repos, wouldn't it be okay to keep repo B in repo A and merely add repo B to repo A's .gitignore?Kernan
I was thinking of doing what Fabien suggests, is there a problem with doing it that way?Etheleneethelin
I fail so see how a symlink solves anything. If I symlink a directory to a subproject into my main project that has a .git directory in it won't it be like I just nest it there without any submodule/subtree setup with all the same issues?Lamelliform
I keep the git repositories separate and copy over changes made to REPO-B in a copy of REPO-B (without .git) that is nested in REPO-A. I do that with rsync. I run rsync -avh --delete --exclude='.git' REPO-B/ REPO-A/REPO-B-copy/ after there are any changes to REPO-BPaperboy
But changes in theses files will not be detected by git in one of the repo...Ray
symlinks will make it difficult when your repo is a react code that needs to be built. Will have to provide all sorts of magic to solve that one.Curley
@Paperboy This is an interesting solution. But one I fear could be fraught with issues. I would recommend against it.Annal
V
38

Yes, you can do exactly what you're asking with the file hierarchy you drew. Repo-B will be independant and have no knowledge of Repo-A. Repo-A will track all changes in it's own files and Repo-B's files.

However, I would not recommend doing this. Every time you change files and commit in Repo-B you'll have to commit in Repo-A. Branching in Repo-B will mess with Repo-A and branching in Repo-A will be wonky (trouble removing folders, etc.). Submodules are definitely the way to go.

Voussoir answered 11/1, 2011 at 16:43 Comment(7)
Can't you simply add REPO-B to /REPO-A/.gitignore?Nibbs
@Nibbs I had the exact same idea. We are currently using subverion for our main project and use a git repo in one of the subfolders. With SVN I just added the folder with the git repo to the svn:ignore property and I was asking myself if I can do the same with git.Gunas
Well I can't see why adding a nested git repo to the ignore list of the parent repo should not work.. But at the same time I have a feeling there must be some catch I haven't thought of, since this approach is rarely seen suggested, and many people discourage nested git repos.Nibbs
I just implemented this exact scenario. I have some uncompressed CSS files in a subfolder that I don't want pushed to the remote repo, so it's in my .gitignore. But I do want to track changes to these files locally. I set up a repo inside the folder with the uncompressed files and added all the files to that repo. It is still ignored by the parent repo but I can track changes inside the sub-repo. Recommended or not, this solution is key for certain situations like this.Catiline
I get that whenever you switch branches in one repository the other will see a whole bunch of changes, but why will "branching in Repo-A will be wonky (trouble removing folders, etc.)."? Thx!Insolvable
@Nibbs adamyonk wanted to "be able to push all of REPO-A's contents to REMOTE-A." I presume he considers REPO-B to be part of REPO-A; hence he mustn't add REPO-B to /REPO-A/.gitignore because then he won't be able to do what he wanted to be able to do.Leifleifer
To state that a submodule does not need to be tracked by its parent repository, without relying on .gitignore, see this answer https://mcmap.net/q/13846/-ignore-new-commits-for-git-submoduleKernan
O
13

You can use a .gitignore file in the parent A repository (ignoring B), but firstly making sure that the B repository is not currently being tracked: commit the parent .gitignore before adding the second B repository.

Otilia answered 13/1, 2021 at 12:32 Comment(3)
OP specifically asked how to push ALL contents of Repo A, presumably including Repo B, so this would not work.Corliss
@Nate311 then this probably could be done by ignoring B/.git so that A/ wouldn't read it as a git repository. If this still doesn't satisfy you, as B/ metadata wouldn't be contained there, then I recommend using git as it was engineered to be used.Otilia
I'm just saying what OP asked for. It's not about whether I personally am satisfied or not.Corliss
O
6

You can achieve what you want (that REPO-A repo contains all the files, including those in folder REPO-B instead of only a reference) by using "git-subrepo":

https://github.com/ingydotnet/git-subrepo

It still works if some of your contributors don't have the subrepo command installed; they will see the complete folder structure but won't be able to commit changes to the subrepos.

Oxytocic answered 27/5, 2020 at 7:50 Comment(0)
N
4

For people coming here a few years after the question was first posted:

git subtree is what you're looking for:

$ git clone https://..../REPO-A
$ cd REPO-A

# Create a remote alias for the REPO-B, for convenience
$ git origin add REPO-B  https://..../REPO-B

# clone REPO-B
$ git subtree pull --prefix=REPO-B REPO-B main --squash

# Develop as you wish, do commits to both REPO-A and REPO-A/REPO-B
# All changes will be pushed to REPO-A but not to REPO-B

# When/if you want to merge things back to REPO-B
$ git subtree push --prefix=REPO-B REPO-B main

# When you want to pull new changes for REPO-B just repeat the pull
$ git subtree pull --prefix=REPO-B REPO-B main --squash

If someone else clones REPO-A they will also get REPO-B's contents (unlike git submodule) but they won't have the remote spec. To them it'll be as if REPO-A is a single repository.

You can read more about git subtree at: https://www.atlassian.com/git/tutorials/git-subtree

Noma answered 24/9, 2022 at 14:43 Comment(0)
R
3

Lots of choices, the best one depends on your purpose:

  • if want to keep the parent as a container of different apps, and some of them could eventually become repos, just use bare Git to treat them as different repos (no submodules no subrepos). No need to learn more git features.

  • if you want to keep the parent as a "project" of different repos and feeling safe on managing access for different collaborators, the solution of using symbolic links for different repo folders is a good option. Again, no need to learn more git features.

Explanation:

If one of the app becomes a repo, just git init there, add the remote repo and forget git tutorials and spend that time for the apps. It just work, and in the parent repo the commits can still be atomic for the rest of apps, and sometimes there will be extra commits,yes, but you do not need to commit parentA for each commit of repoB. You can apply different permisions on both repos (although parent can have repoB code unless you use .gitignore to ignore the repoB) .

Rosalba answered 7/5, 2021 at 13:12 Comment(0)
D
3

In my case, I didn't want to merge repo A with repo B so the repo inside the repo works perfectly fine. Just carefully update the .gitignore for both repos. And make sure to stay inside the respective dir while using git commands.

Some quick notes:

  1. Both repos will act independently and thus can not be merged.
  2. Parent repo will contain all the changes inside subfolders and files unless added to its .gitignore
  3. Child repo will contain all the changes inside its subfolders and files unless added to its .gitignore.
  4. Parent and Child's .gitignore files will act independently of each other. So, for example, if you want to ignore a file in the child repo but want to push it in the parent repo, just add the file in the child repo's .gitignore
  5. In case both repos need to be merged, the above guide will be considered invalid. So, the overall case should be studied properly to use the repo inside the repo strategy.
Dibrin answered 19/12, 2021 at 15:11 Comment(0)
S
1

There is one more way this could be handled. You can place the repos(that are submodules) as each separate independent repository. And can create softlinks to the submodule repos inside the master repo.

$ ls
$ main-repo submodule1 submodule2 

$ ln -s submodule1 main-repo/submodule1
$ ln -s submodule2 main-repo/submodule2

Once files inside main-repo are listed, the submodules SoftLinks are listed

$ ls main-repo/
$ other-files submodule1 submodule2
Sanctified answered 24/3, 2022 at 16:56 Comment(0)
P
0

Simplest I found is to edit REPO-A's .git/info/exclude

$vim .git/info/exclude

it should look something like this. Just added the last line below.

# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
REPO-B/
Preferential answered 20/7, 2022 at 16:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.