0

I'm trying to set up a branch such that branchA has subfolders A and B, but B contains the contents of branchB.

I've been looking at submodules, subtrees, and subrepos, but I can't figure out what would do what I am looking for.

In order to prevent this from becoming an XY problem, my overarching situation is this: I'm developing an HTML5/JS game and I want to be able to test it on Github Pages.
So I want branch/subdirectory gh-pages/play to contain the branch master.

CodeWizard
  • 128,036
  • 21
  • 144
  • 167
Dessa Simpson
  • 1,232
  • 1
  • 15
  • 30

1 Answers1

1

Branches don't have folders / directories. Branches are, quite simply, pointers to commit hash IDs (they start out as little files containing the raw hash ID, although they can be compressed into a sort of database of name-to-ID mapping, which Git does to save time and space for names that are not constantly changing). So it's not possible directly.

It is possible to do what you want with submodules, though. It's just tricky. You will have to be very careful. It's also not at all clear to me whether it will work at all with whatever this GitHub Pages thing may be, since they have to do a clone-and-checkout-with-submodule operation.

A Git submodule is really just another Git repository: you tell Git that some directory ("folder") such as B should be made by cloning a different Git repository, from some specific URL. Once the clone is done, Git should then cd into the directory that the git clone makes, and git checkout one specific commit, by hash ID.

Well, what if for the "different" Git repository you want git://host.name/path/to/url.git to check out into sub-directory B, you specify the URL git://host.name/path/to/url.git?

The obvious danger here is the potential for endless recursion: Git checks out url.git, sees that it has a submodule, clones url.git to subdirectory B, checks out the commit inside B, sees that it has a submodule, clones it, cds to what is now B/B, sees that it has a submodule, clones it, goes into B/B/B, sees that it has a submodule...

You avoid this endless recursion by:

  • cloning without recursive submodule extraction (this is the default for git clone), and/or
  • making very sure never to have the specific commit for the submodule include a commit that has the submodule as a submodule.

There's still one more problem: submodules check out one specific commit by hash ID, not by branch name. You wanted B to be a self-clone that checks out branch master (which presumably never has a self-submodule B). But all you can get is a B that checks out a specific Git hash ID, which is the hash ID you have stored in the commit in the superproject (which of course is this same repository).

There are some ways to dislodge the submodule off its one-specific-commit, including ways to make it check out a branch by branch-name. These require running specific git submodule commands, which is part of what may prevent you from doing this on GitHub Pages (whatever that is, again). But, assuming they let you do the submodule thing at all, you don't necessarily have to have it go by name: you can just make a new commit that stores the new master hash into the superproject.

Say, for instance, you're on branch develop in this superproject-with-self-as-submodule. In develop, there's a .gitmodules file that says "I have a submodule / subproject you should clone into B, using this here URL" (which is the superproject's URL). At the tip commit of develop you have a commit containing a "gitlink" tree entry that says "make a clone into B, looking up the subproject's URL in .gitmodules, and using hash deadb0a"—which is the hash of the tip commit of branch master.

Once you advance the tip of master to a new commit ac0ffee, you check out develop and make a new commit that has a "gitlink" tree entry that says "make a clone into B using hash ac0ffee". Nothing else changes—just the hash ID—but now, when someone checks out develop with submodules enabled, they get the same commit in B that they would by checking out branch master in B, because branch master says "check out hash ac0ffee".

(Obviously this whole thing is a bit error-prone, as are submodules in general. I suspect this is not a very wise path to go down. But in theory, at least, it can work.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • Fun fact: submodules can now track branches. – Dessa Simpson Apr 08 '17 at 17:58
  • @DuncanXSimpson: Hence *There are some ways to dislodge the submodule off its one-specific-commit, including ways to make it check out a branch by branch-name. These require running specific git submodule commands ...* You have to set the name of the branch (which I think you can save in the committed `.gitmodules` file) and then run `git submodule update --remote` or `git submodule checkout --remote`. – torek Apr 08 '17 at 20:55