Chapter 11

Dependencies between Repositories

In Git the repository is the release unit, in the sense that a version, branch and tag can only be created on a whole repository. If a project contains subprojects that each has its own release cycle and thus its own versions, there must also be a repository for each subproject.

The relationship between the main project and the sub-projects can be implemented with Git submodule or subtree command.

Note

The subtree command is first officially included in Git in version 1.7.11. However, it is only an optional component located under the contrib directory. Some Git installation packages include the subtree command automatically, others require manual installation.

The main difference between the submodule and subtree concepts is that with submodules the main repository only references the module repositories, whereas with subtree the contents of the module repositories are imported into the main repository.

Dependencies with Submodules

With submodules, a module repository can be embedded into the main repository. For this purpose, a directory with a commit in a module repository will be linked to the main repository.

Figure 11.1 shows the basic structure. There are two repositories: main and sub. In the main repository, the sub directory will be linked with the module repository. In the workspace of the main repository there is a complete module repository under the sub directory. The actual main repository will only reference the module repository. For this purpose, there is a file named .gitmodules, in which the absolute path to each module repository is defined.

[submodule "sub"] 
path = sub 
url = /project/sub

In addition to the .gitmodules file, the references to submodules are also stored in the .git/config file. This is done when you call the submodule init command, which reads the .gitmodules file and writes the information in the .git/config file. This indirect configuration allows the paths to the module repositories to be adjusted locally in the .git/config file.

[core] 
repositoryformatversion = 0 
filemode = true 
bare = false 
logallrefupdates = true 
ignorecase = true 
[submodule "sub"] 
url = /project/sub

Figure 11.1: The fundamentals of submodules

With the previous information it would not be possible for each commit in the main repository to reproduce the corresponding version of the module repository. As such, the commit in the module repository is still needed. This will be stored in the object tree in the main repository. The following is the object tree. The third entry, sub, is a sub-module, which can be recognized by its commit type. The hash that follows references the commit in the module repository.

100644 blob 1e2b1d1d51392717a479eaaaa79c82df1c35d442    .gitmodules
100644 tree 19102815663d23f8b75a47e7a01965dcdc96468c    src
160000 commit 7fa7e1c1bd6c920ba71bd791f35969425d28b91b  sub

If a repository that contains submodules is cloned, you must call the submodule init command. This command will transfer the URLs of the submodules in the .git/config file. Subsequently, calling the submodule update command will clone the directories of the module repositories.

You can view the hash of a referenced commit in a submodule using the submodule status command. Any tag will be shown in brackets at the end of the output.

> git submodule status

091559ec65c0ded42556714c3e6936c3b1a90422 sub (v1.0) 

Git always refers to exactly one commit in the module repository. Meanwhile the commit hash is also part of every commit in the main repository. It follows that new commits in the module repository are not automatically recorded in the main repository. This behavior is explicitly intended, so that you have to obtain the matching project version in the module repository when restoring a project version in the main repository.

If you intend to use a new version of the module repository in the main repository, you have to explicitly change this.

If you are working in the main repository and at the same time working in the module repository, then you have to commit changes to both repositories. If you have a central repository, both repositories must be transmitted separately using the push command.

After every update to a workspace that contains submodules, you should call the submodule update command to get the correct versions of the submodules.

If an entirely new submodule has been added, then before calling the submodule update command you should call submodule init.

As a developer, it is good enough if you run the init-update sequence after each update to the workspace (checkout, merge, rebase, reset, pull).

The submodule init command transfers information from the .gitmodules file to the .git/config file only if there is no corresponding entry for the module. As such, the paths to the module repository can be adjusted locally. However, if another developer changed the official path of the .gitmodules file, the change will not be accepted. The submodule sync command does exactly this task. It updates the paths in the .git/config file and overwrites any local changes.

Dependencies with Subtrees

With subtrees, module repositories can be embedded into a Git repository. For this purpose, a directory in the repository is associated with a commit, a tag or a branch in a module repository. Unlike submodules, however, the entire content of an embedded module repository is imported and not just referenced in the main repository. This makes the main directory self-sufficient to work against.

Figure 11.2: The fundamentals of subtree

Figure 11.2 shows the basic structure. There are two repositories: main and sub. The sub directory in the main directory is linked with the module directory (using the subtree add command). In the main repository, under the sub directory, there are files from a version of the module repository.

Technically, the subtree add command imports all commits from the module repository to the main repository (See commits S1 and S2). Then, the current branch of the main repository is linked with the specified commit in the module repository (See merge commit G3). Internally, the subtree merge strategy (--strategy=subtree) is used. This results in a merge in the specified directory, so that the content of the module repository lands under the sub directory.

Unlike submodules, when cloning a repository that has subtrees, there is nothing special to be observed. The normal clone command will pick up the main repository and all the module repositories it contains.

> git clone /path-to/main

Also with subtrees, it is possible to make changes in the embedded module directories. Here, nothing special needs to be done. You simply use the normal commit command. You can version changes in the main repository and one or more module directories in one commit.

Only when retransmitting the module changes in the respective repository do you need to take special precautions.

As can be clearly seen from the above, most subtree operations are simpler than those of submodules. Only extracting the changes is similarly complex.

In many scenarios, however, no extraction is required, as you would work in the main repository and not in the module directory.

Summary

  • Embed a submodule: Use the submodule add and submodule init commands to embed a submodule.
  • Clone a project that contains submodules: After cloning the project, use the submodule init and submodule update commands.
  • Select a new version of a submodule: First, select the new commit in the submodule directory (using the checkout command). Then, do a commit in the main repository.
  • Handle the module repository and main repository simultaneously: it must be carried out with the commit in the module repository first and then with the commit in the main repository. Both repositories must be pushed separately with the push command.
  • Embed a subtree: Use the subtree add command to embed a subtree.
  • Select a new version of the subtree: The subtree pull command updates the module directory to the desired branch or tag.
  • Extract changes in the module directory: The subtree split command creates a separate branch that includes the changes in the module directory. Using the merge command, these changes can then be merged with the other changes and pushed using the push command.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.123.155