git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Notes on Using Git with Subprojects

From
A Large Angry SCM <gitzilla@gmail.com>
Date
Oct 1, 2006, 05:19 UTC
Message-ID
<451F4FCA.7060804@gmail.com>
In-Reply-To
<45196628.9010107@gmail.com>

This updates the note based on the discussion the original note generated. The most significant difference is the ability to specify a particular version of a subproject.

							20061001.0400

Notes on Using Git with Subprojects =================================== Copyright (C) 2006 by Raymond S Brand

Git does not have native support for subprojects and this is a good thing because managing subprojects is better handled by the project build machinery. Managing subprojects with the project build machinery is more flexible than the native support from an SCM and allows the use of different SCMs by different subprojects. However, there is a lot of interest in using Git for the SCM of a project with subprojects.

Git, unfortunately, does not make it easy. What is wanted is to put all of the subprojects in one repository and be able to checkout the various parts from a local copy of the repository. The problem is, with Git, a repository can have at most one working directory associated with it at a time. This is because Git stores a lot of information about the contents of the working directory in the repository. In fact, the usual situation is that the repository, itself, is in the working directory.

An important criteria for supporting subprojects is that a subproject may be developed and controlled by an entity or organization different than that of the parent project of the subproject. As a consequence of this, the build machinery needed to manage a project controlled by another entity as a subproject must be in the parent project.

This note describes a method to use Git with subprojects; other methods are also possible.

Definitions
-----------
Parent Project:
	A project that logically contains one or more subprojects.
Project:
	A set of files that is (relatively) self contained with respect
	to changes and treated as a unit by the SCM.
Root Project:
	A project that is not a subproject.
Subproject:
	A project logically contained in another project.
Super project:
	A project composed of subprojects.

Setup ----- All subprojects are contained in a single repository and referred to by separate heads or tags. Developers create a local copy of the project repository; hereafter, referred to as the "local master repository" or just "local master". All fetches, pulls and pushes by the developers with the "local master" of other developers should be to and from their own "local master".

Root Project Checkout --------------------- The root project is the project that all of the subprojects are a part of. It is a parent project of one or more subprojects; each of which may also be parent projects to other subprojects.

To checkout the root project, choose an name for the project working directory (the working directory must not already exist) and perform the equivalent of the following commands.

	git-clone -s -n $LOCAL_MASTER $ROOT_DIR \
		&& cd $ROOT_DIR \
		&& git-checkout -b $ROOT_BRANCH--local $ROOT_VERSION
Where:
	$LOCAL_MASTER is the path to the "local master"
	$ROOT_DIR is the name of the working directory to use
	$ROOT_VERSION is the ref name of the root project state
	$ROOT_BRANCH--local is a branch for local changes

This will leave the current working directory of the shell in the project working directory.

This also creates a branch with the suffix of "--local" to hold all of the local working directory commits and modifications. The $ROOT_BRANCH is used as a tracking branch so that upstream changes can be fetched into the working repository without affecting the checked out files.

Once the root project is checked out, the subprojects are checked out.

Subproject Checkout ------------------- Each project that is a parent project needs to checkout all of the subprojects of the project. Each subproject is checked out with the equivalent of the following bash commands:

	git-clone -s -n $LOCAL_MASTER $SUBPROJECT_DIR \
		&& ( cd $SUBPROJECT_DIR \
			&& git-checkout -b $SUBPROJECT_BRANCH--local \
				$SUBPROJECT_VERSION
		)
Where:
	$LOCAL_MASTER is the path to the "local master"
	$SUBPROJECT_DIR is the directory name of the subproject
	$SUBPROJECT_VERSION is the ref name of the subproject state
	$SUBPROJECT_BRANCH--local is a branch for local changes
	

Project Development ------------------- Changes to a project are performed in the working directory of the project and are recorded in the repository in the working directory on the $PROJECT--local branch.

Receiving Project Upstream Changes ---------------------------------- Upstream project changes are first fetched into the project tracking branch of the local master repository and are then fetched into the project tracking branch of the working directory repositories. To merge upstream changes into the working directory, a pull from the project tracking branch of the working directory repository executed.

	# Fetch project branch from upstream to local master
	(cd $LOCAL_MASTER && git-fetch $UPSTREAM $PROJECT_BRANCH)
	# Fetch project branch from local master to working repo
	git-fetch $LOCAL_MASTER $PROJECT_BRANCH
	# Merge upstream changes in to working directory
	git-pull --no-commit . $PROJECT_BRANCH
Where:
	$LOCAL_MASTER is the path to the "local master"
	$UPSTREAM is the Git URL of the upstream repository
	$PROJECT_BRANCH is the branch name of the (sub)project

Sending Project Changes Upstream -------------------------------- To send project changes upstream from a working directory repository, the changes are first pushed to a branch in the local master repository, $PROJECT--$IDENT. The changes can then be pushed or pulled from the local master repository.

	# Push project changes to local master
	git-push $LOCAL_MASTER \
		$PROJECT_BRANCH--local:$PROJECT_BRANCH--$IDENT
	# Push project changes from local master to upstream
	(cd $LOCAL_MASTER && git-push $UPSTREAM \
		$PROJECT_BRANCH--$IDENT:$PROJECT_BRANCH--$NICK--$IDENT)
Where:
	$LOCAL_MASTER is the path to the "local master"
	$UPSTREAM is the Git URL of the upstream repository
	$PROJECT_BRANCH is the tracking branch of the (sub)project
	$PROJECT_BRANCH--local is a branch for local changes
	$IDENT is a label unique for this set of working directories
	$NICK is a (branch name safe) identifier of the developer

Automation ---------- The following proof of concept code can be added to parent project makefiles to automate most of the operations needed to support subprojects with Git.

 ---->8----  ---->8----  ---->8----  ---->8----  ---->8----  ---->8----
# Add this to the makefiles
SUBPROJECTLIST := GIT:s1_ref:s1_dev:s1 \ 
		  GIT:s2_ref:s2_dev:s2 \ 
		  GIT:s3_ref:s3_dev:s3
include Git_machinery.make
# Rest of the Makefile
 ---->8----  ---->8----  ---->8----  ---->8----  ---->8----  ---->8----
# Git_machinery.make

GIT-CLONE := gitclone GIT-CHECKOUT := gitcheckout GIT_FETCH := gitfetch GIT-PULL := gitpull GIT-PUSH := gitpush

include GIT-SUBPROJECT-VARS.mak
GIT-SUBPROJECT-VARS.mak: Makefile
	@rm -rf GIT-SUBPROJECT-VARS.mak
	@echo "REPOSITORY := $(REPOSITORY)" > GIT-SUBPROJECT-VARS.mak
	@echo "IDENT := $(IDENT)" >> GIT-SUBPROJECT-VARS.mak

# SUBPROJECTLIST has the following format: # Each "word" in the list starts with a scheme identifier followed # by a ':'. The reainder if the "word" is the scheme specific # subproject details. # Scheme: GIT # The scheme specific subproject details are 3 fields separated by # ':'s. # Field 1: Version reference - reference to checkout and fetch # from. # Field 2: Development branch ref name. # Field 3: Sub directory for the subproject.

GIT--subproject--setup::
	for SUBPROJECT in $(filter GIT:%,$(SUBPROJECTLIST)) ; do \
	  PARAM=($$(echo $$SUBPROJECT | tr ':' ' ')) ; \
	  $(GIT-CLONE) -s -n $(REPOSITORY) $${PARAM[3]} \
	  && ( cd $${PARAM[3]} \
	    && $(GIT-CHECKOUT) -b $${PARAM[2]}--local $${PARAM[1]} ; \
	  ) ; \
	done
GIT--subproject--fetch::
	@for SUBPROJECT in $(filter GIT:%,$(SUBPROJECTLIST)) ; do \
	  PARAM=($$(echo $$SUBPROJECT | tr ':' ' ')) ; \
	  ( cd $${PARAM[3]} \
	    && $(GIT-FETCH) $(REPOSITORY) $${PARAM[1]} ; \
	  ) ; \
	done
GIT--subproject--pull::
	@for SUBPROJECT in $(filter GIT:%,$(SUBPROJECTLIST)) ; do \
	  PARAM=($$(echo $$SUBPROJECT | tr ':' ' ')) ; \
	  ( cd $${PARAM[3]} \
	    && $(GIT-FETCH) $(REPOSITORY) $${PARAM[1]} ; \
	    && $(GIT-PULL) --no-commit . $${PARAM[1]} ; \
	  ) ; \
	done
GIT--subproject--push::
	@for SUBPROJECT in $(filter GIT:%,$(SUBPROJECTLIST)) ; do \
	  PARAM=($$(echo $$SUBPROJECT | tr ':' ' ')) ; \
	  ( cd $${PARAM[3]} \
	    && $(GIT-PUSH) $(REPOSITORY) \
	      $${PARAM[2]}--local:$${PARAM[2]}--$(IDENT) ; \
	  ) ; \
	done
 ---->8----  ---->8----  ---->8----  ---->8----  ---->8----  ---->8----

The example Makefile code has a number of limitations: There is no error handling. It only handles Git managed subprojects. There are other Git commands that can be usefully applied to subprojects.

Previous: A Large Angry SCM
Message 39 of 39 in “Notes on Using Git with Subprojects”
  1. A Large Angry SCMSep 26, 2006
  2. Johannes SchindelinSep 26, 2006
  3. A Large Angry SCMSep 26, 2006
  4. Johannes SchindelinSep 26, 2006
  5. A Large Angry SCMSep 26, 2006
  6. Daniel BarkalowSep 26, 2006
  7. Shawn PearceSep 26, 2006
  8. A Large Angry SCMSep 26, 2006
  9. Martin WaitzSep 27, 2006
  10. Johannes SchindelinSep 27, 2006
  11. Martin WaitzSep 27, 2006
  12. Johannes SchindelinSep 27, 2006
  13. Sven VerdoolaegeSep 27, 2006
  14. Junio C HamanoSep 27, 2006
  15. Michael S. TsirkinSep 28, 2006
  16. Jeff KingSep 28, 2006
  17. Martin WaitzSep 27, 2006
  18. Johannes SchindelinSep 27, 2006
  19. A Large Angry SCMSep 27, 2006
  20. Johannes SchindelinSep 27, 2006
  21. Shawn PearceSep 27, 2006
  22. Rogan DawesSep 27, 2006
  23. Shawn PearceSep 28, 2006
  24. A Large Angry SCMSep 28, 2006
  25. A Large Angry SCMSep 28, 2006
  26. A Large Angry SCMSep 27, 2006
  27. Jeff KingSep 27, 2006
  28. A Large Angry SCMSep 28, 2006
  29. Jeff KingSep 28, 2006
  30. Shawn PearceSep 28, 2006
  31. Jeff KingSep 28, 2006
  32. Shawn PearceSep 28, 2006
  33. Shawn PearceSep 28, 2006
  34. Johannes SchindelinSep 28, 2006
  35. Martin WaitzSep 28, 2006
  36. A Large Angry SCMSep 28, 2006
  37. Martin WaitzSep 29, 2006
  38. A Large Angry SCMSep 26, 2006
  39. A Large Angry SCMOct 1, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.