How can I mirror a directory in a git repo into another git repo?
Asked Answered
S

5

16

I have a directory /amp in RepoA and a RepoB (populated with the contents of /amp initially). I want to mirror any changes to the /amp in RepoA into RepoB.

Is it possible ?

P.S: RepoA contains many other directories. I only want to mirror the /amp dir. Whereas RepoB is only going to have the /amp contents not any other.

Superdreadnought answered 19/1, 2017 at 7:21 Comment(1)
Configure contents in /amp as a submodule and add that submodule in both RepoA and RepoB.Jerriejerrilee
H
14

You could use git submodules for this, the first step would be to create a repository from your dir /amp and later use it as a submodule in your other repositories.

To make /amp a repository you could do:

$ cd /path/to/amp
$ git init
$ git add .
$ git commit -m "First commit"

Now let's assume you will be using github, you could publish your repo by doing:

$ git remote add origin [email protected]:<your-user>/amp.git
$ git push -u origin master

Now on repoA and repoB you will need to add the new amp repo as a submodule, this can be done by doing something like this:

$ cd /path/to/repoA
$ git submodule add -b master [email protected]:<you-user>/amp ampMirror

Same for repo repoB

$ cd /path/to/repoB
$ git submodule add -b master [email protected]:<you-user>/amp ampMirror
$ git commit -m "added appMirror submodule"

Notice that the name I am giving to the directory within repoA and repoB is ampMirror but it can be anything you want, indeed you can use the same name by just using:

git submodule add -b master [email protected]:<you-user>/amp 

The directory structure would look something like:

repo(A/B)
├── .git/
├── .gitmodules   <-- created after adding the submodule
├── foo
└── ampMirror
    ├── .git/     <-- repo to keep/track changes for app (need to git pull)
    └── foo

Now every time a change is made into your amp repo you will need to update "pull" the changes in your repositories for example:

$ cd /path/to/repoB
$ cd appMirror
$ git pull
$ cd ..    <--- get back to your project root
$ git commit -am "update submodule" 

Another way of doing this and become useful if have more than one submodule is:

$ cd /path/to/repo(A/B)
$ git submodule foreach git pull origin master
$ git commit -am "updated submodules"

I hope this can help to give you a better idea.

Hachmin answered 8/4, 2018 at 12:25 Comment(1)
A use case is having a Monorepo and publish one of the folder as an independant repo. For instance I create a package library and want to publish some starters. Currently I have a repo for the starter app, and a repo for the library, your solution would apply. But it feel "reversed", in some architecture you'd want to have the monorepo as the source of truth and the isolated repos as mirrors.Ailey
W
6

nbari's answer is correct that submodules are designed to solve this problem.

One potential drawback of submodules is that they are not fully transparent to the user. If you want some people to be able to use RepoA and RepoB without having to know anything about submodules, an alternative is git subtree. The main commands you would have to use are:

  • git subtree split, that can extract subdirectory amp from RepoA to a repository of its own, say RepoAMP (you may also use git subtree push to push the result).

  • git subtree merge that can merge RepoAMP to directory /amp in RepoB (you may also use git subtree pull to download and merge in one command).

In the end, RepoA and RepoB are both "normal" repositories. The mirroring is not done automatically but git subtree helps you doing it properly.

Wenda answered 12/4, 2018 at 15:1 Comment(4)
Sounds more suited for a monorepo setup where you'll want to publish part of the tree as read-only reposAiley
Both use-case actually work: develop on a monorepo and extract&publish some subdirectories, or include a dependency developed in another repo as a subdirectory of a repo. To answer the question, we actually need both, to extract a directory from a repo and merge it into the other.Wenda
Thanks! By the way I think you were my "Introduction to Unix" teacher years ago in engineering school, I am still learning from you hahaAiley
Ha ha, that looks like me indeed :-)Wenda
S
2

simple way of mirroring a directory of git repository into another git repository

git clone --mirror [email protected]/mirror-repository.git

cd mirror-repository.git

push changes to new repository using below command

git push --mirror [email protected]/new-mirror.git

This will get all the branches and tags that are available in the mirror repository and will replicate those into the new location.

Don’t use git push --mirror in repositories that weren’t cloned by --mirror as well. It’ll overwrite the remote repository with your local references (and your local branches).git clone --mirror is prefered over git clone --bare because the former also clones git notes and some other attributes.

Sousa answered 31/1, 2022 at 8:36 Comment(0)
D
0

If RepoB is going to have just /amp content than it is more correct to make a library from it. Put this library as dependency to your project in RepoA. How to do it depends on language (package manager) that you use.

For dev environment you can create symlink in RepoA that will point to RepoB.

Davena answered 19/1, 2017 at 10:15 Comment(3)
But how would git recognize symlinks? When I commit, symlinks get committed, not the reference (or target).Superdreadnought
You should commit changes in RepoB (lib) only inside it. They are different repos for some reason. May be later RepoC will use RepoB too. If you change lib inside the project you can break other projects that use it.Davena
I did commit inside RepoB, though. But I've found a workaround for my case. I just nested the RepoB into A. Initialized RepoB in amp folder. It works as I expected, right now.Superdreadnought
P
0

If submodule are not to your liking, an alternative approach would be a content filter driver in a .gitattributes of repoA, for all files in /amp/.

See Pro Book:

https://static.mcmap.net/file/mcmap/ZG-AbGLDKwfnZ73tbRMtKmMva3/book/en/v2/images/clean.png

More specifically, a "clean" filter would be called automatically on git commit (only for /amp/** files), and could then perform the necessary command in order to replicate the changes in repoB.

That clean merge driver script would be:

#!/bin/sh
git --work-tree=/path/to/repoA/amp --git-dir=/path/to/repoB/.git add .
git --git-dir=/path/to/repoB/.git commit -m "import from repoA/amp"
Palp answered 8/4, 2018 at 14:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.