10

I have a complicated Ionic project I'm developing. Many of the components and providers I'm developing are generic and can be used in other projects my company is doing. This is common in software development. This is the Git workflow I have come up with (this graph shows branches):

my-company-library-repo ----
                            |_ component 1 feature branch
                               |_ company component 1 feature branch testbed
                            |_ component 2 feature branch

The final component code (just a .ts or .js file) developed in the testbed is pushed to component feature branch. The testbed code stays in the testbed branch. Also in the feature branch goes any docs that might accompany the component.

Now in the application repo I add the feature branch as a subtree using this command:

git subtree add -P <destination-dir/feature> --squash <my-company-library-repo-url> <feature-branch-name>

And that gave me the following (this graph shows folder structure):

my-app-repo-------
                  |_ company-library-feature-subtree

This should only contain the .js or .ts and it's docs in it's subfolder. I get this only to work part way. When it pulls the subtree, it does only pull the component and it's doc files, but the files get pulled into a very long list of sub-directories like this:

my-app-repo/src/feature-branch/feature/src/app/providers/...

This makes it hard to use the library because the files are put so many directories (unused directories) deep.

So, when I push my 2 files from the feature-testbed branch to the feature branch, how can I not pull that whole directory structure with them?

Scott Weldon
  • 9,673
  • 6
  • 48
  • 67
juliet
  • 421
  • 3
  • 13
  • Please [edit] your post to add any additional information you have to your question. Avoid adding this in the comments, as they are harder to read and can be deleted easier. I've [edited](//stackoverflow.com/help/editing) the information from your existing comments into your question. – Scott Weldon Oct 26 '16 at 18:02
  • 1
    Note that the word *push* in Git has a special meaning: you do not push files, you push commits, and this transfers them from one repository to another. Likewise, *branch* has specialized definitions (and is, unfortunately, ambiguous), none of which cross repositories; and *pull* means *fetch-then-merge*, with *fetch* and *merge* also being specialized jargon. `git subtree` is complicated because it deliberately mixes multiple repositories, commits, and branches, trying to do them all at once. @ScottWeldon's edits have helped a lot here, but it's still going to be confusing. :-) – torek Oct 26 '16 at 19:22
  • A few options for similar question are described in https://stackoverflow.com/questions/23937436/add-subdirectory-of-remote-repo-with-git-subtree/30386041#30386041 – Michael Freidgeim May 11 '19 at 06:18

2 Answers2

13

Before adding the subtree to my-app-repo, split a subtree from my-company-library-repo:

# In my-company-library-repo
git subtree split -P src/app/providers/... -b feature-new feature

This will create a new history with the contents of src/app/providers/... at the root of the repo, starting at the feature branch, and create the branch feature-new at the end of this history.

Then add that new branch as a subtree to my-app-repo:

# In my-app-repo
git subtree add -P <destination-dir/feature> --squash <my-company-library-repo> feature-new

Now you will have the contents of src/app/providers/... at <destination-dir/feature>.

You didn't mention whether you will be repeating this process regularly, but that is possible too. From the git-subtree man page:

Repeated splits of exactly the same history are guaranteed to be identical (ie. to produce the same commit ids). Because of this, if you add new commits and then re-split, the new commits will be attached as commits on top of the history you generated last time, so 'git merge' and friends will work as expected.

Scott Weldon
  • 9,673
  • 6
  • 48
  • 67
10

I researched Scott Weldon's solution. It would work, but it seems git subtree splits the said directory into its own repo. At least that's what I gleaned from reading man pages and books and what not. (If I'm wrong, which may well be the case, please let me know.) That's not what I wanted to do.

I did, however, find the solution to my problem. Here's what I did using the Git Subtree Merge Strategy (instead of the GIT SUBTREE command) in my project:

$ git remote add my-library <my-library-url>
$ git fetch my-library
$ git checkout -b my-library-branch my-library/master
$ git checkout master
$ git read-tree --prefix=<desired/library/dir> -u my-library-branch
$ git commit -m "Merged library project as subdirectory"
$ git push

This worked great. I have my library in a reasonable subfolder. Admittedly, I have to take the whole library, not just a chunk like a custom component or provider, but that's OK in this case.

juliet
  • 421
  • 3
  • 13