📜 ⬆️ ⬇️

External dependencies in the gita: submodule or subtree?

Long ago, I learned that dependencies should be stored with the project code. Then, when you return to the old version of the code, it is much easier to restore the environment.

My project has several dependencies. Most of the dependencies live in the git repositories. The project itself also lives in the gita.

One of the libraries we use is frequently updated. We are sitting on the developer version, and often we ourselves commit to it the code that is required by our project. That is, it is required to promptly skip our edits through the main repository of this library — you don’t want to create and maintain your fork for a number of reasons.
')
Previously, I simply copied the dependencies to the project folder, and added to each file a VERSION.TXT with its version. But, if you need to work with the current version of third-party code, it is inconvenient. Yes, and copy files by hand when there is a git is somehow stupid. I want to find a more modern solution.

The most widely advertised and fashionable feature for working with third-party repositories is git submodules (“submodules”). Naturally, first of all I began to look at her.

Before that, I had already tried working with sub-modules in home projects. While one person uses the repository carefully, there are no special problems. In any case, it is much more convenient than copying the code by hand.

However, as soon as I tried to transfer my experience to a more serious workflow, it turned out that not everything is so simple.

This is what we encountered:
In general, quite unpleasant. Each of the problems can somehow be circumvented, but there are too many problems and new ones constantly appear.

From submodules had to be abandoned.

But every cloud has a silver lining. Knowledgeable people suggested that in gita for a long time (even before 1.5.2) there exists an alternative solution - subtree merge strategy (“subtrees”).

The idea is to take the commit history from the external project and redirect it to the internal subdirectory. It uses the standard guitar mechanism for working with external branches.

Example from the documentation: add the code from the master repository branch Bproject (lies in / path / to / B) to our project in the dir-B / subdirectory.

$ git remote add -f Bproject /path/to/B
$ git merge -s ours --no-commit Bproject/master
$ git read-tree --prefix=dir-B/ -u Bproject/master
$ git commit -m "Merge B project as our subdirectory"

You need to pay attention to the -f switch of git remote add. He tells the gita to immediately fetch this remote.

Further, the changes in Bproject are tightened with the git pull command with explicit indication of the desired branch and merge strategy:

$ git pull -s subtree Bproject master

If the corresponding remote-in subtree is not added to the working copy, the history of the main repository does not show the name of the branch from which the changes are pulled.

The problem is purely cosmetic, and does not affect the work. It is treated by adding this remote to the working copy:

$ git remote add -f Bproject /path/to/B

In the future, if new branches appear, you can pull up the changes in the remote:

$ git fetch Bproject

There are a couple of drawbacks:
  1. As in the case of the usual merging of branches, in the commit logs, the history of the subtree is mixed with the history of the main project.
  2. Submitting changes to a subtree design is much more complicated than with submodules. But it's easy to get around by making changes to a separate clone of this project.
None of these shortcomings is critical to our workflow.

Working with subtrees is much more convenient than with submodules. It does not need to re-educate users, it is easier to automate. Subtrees easier to maintain. Recommend.

By the way, on Gitkhab there is a project aimed at developing work with subtrees: git-subtree .

Additional reading:
  1. Pro Git: Submodules
  2. Pro Git: Subtree Merging

Source: https://habr.com/ru/post/75964/


All Articles