183

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?

adamyonk
  • 2,976
  • 4
  • 22
  • 23
  • 2
    one of the simple and popular ideas below, just git ignore REPO_B: `cd REPO-A && touch .gitignore && echo "./REPO-B" >> .gitignore`. – anon01 Jan 28 '21 at 07:21

10 Answers10

168

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.

cnvzmxcvmcx
  • 1,061
  • 2
  • 15
  • 32
mipadi
  • 398,885
  • 90
  • 523
  • 479
  • 32
    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 ;) – VonC Jan 11 '11 at 16:06
  • 1
    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. – Damien Wilson Jan 11 '11 at 16:10
  • 3
    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? – JohnO Jan 11 '11 at 19:08
  • 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?". – Symbolic Oct 05 '19 at 04:45
91

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

JohnO
  • 1,889
  • 1
  • 12
  • 15
  • 22
    for how confusing git submodules and git sub-tree seem be, this is a valid answer. – Trevor Hickey Jan 26 '14 at 03:58
  • This is also very useful for assembling one application from multiple remote repositories – GeraldScott Sep 25 '16 at 06:30
  • 45
    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`? – Fabien Snauwaert Aug 24 '17 at 13:39
  • 1
    I was thinking of doing what Fabien suggests, is there a problem with doing it that way? – theonlygusti Jun 14 '18 at 22:43
  • 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? – redanimalwar Sep 01 '18 at 09:06
  • 4
    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-B – Shai Sep 25 '18 at 18:46
  • But changes in theses files will not be detected by git in one of the repo... – Ludovic Feltz Nov 14 '19 at 09:11
  • 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. – zookastos Aug 20 '20 at 06:31
37

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.

kubi
  • 48,104
  • 19
  • 94
  • 118
  • 77
    Can't you simply add REPO-B to /REPO-A/.gitignore? – mikkelbreum May 01 '14 at 12:10
  • 2
    @mikkelbreum 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. – 2ndkauboy Jun 10 '14 at 10:05
  • 3
    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. – mikkelbreum Jun 10 '14 at 11:48
  • 26
    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. – Mageician May 04 '15 at 14:21
  • 1
    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! – user2688151 Sep 01 '16 at 03:48
  • 1
    @mikkelbreum 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. – HelloGoodbye Jul 21 '17 at 21:02
  • To state that a submodule does not need to be tracked by its parent repository, without relying on `.gitignore`, see this answer https://stackoverflow.com/a/43440263/1717535 – Fabien Snauwaert Aug 24 '17 at 12:46
12

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.

Iacchus
  • 2,671
  • 2
  • 29
  • 24
  • 2
    OP specifically asked how to push ALL contents of Repo A, presumably including Repo B, so this would not work. – Nate311 Jun 07 '23 at 00:11
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.

Glue
  • 63
  • 1
  • 4
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) .

angelito
  • 412
  • 4
  • 10
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.
Hugh W
  • 716
  • 2
  • 10
  • 33
StealthTrails
  • 2,281
  • 8
  • 43
  • 67
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
SuperNova
  • 25,512
  • 7
  • 93
  • 64
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/
Chetan
  • 644
  • 6
  • 7
0

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

V13
  • 853
  • 8
  • 14