开发者

Alternate/multiple directory structure mappings within a git repository

I manage a largish (23,000 LOC for includes/src, 5000 LOC for samples), multi-platform, ANSI C code library used on everything from an 8-bit embedded processor with 32KB of flash, up to a desktop PC running Windows. This code base will continue to grow, and we'll be adding more platforms to it.

I'm currently using Subversion to maintain it, but the company is moving to git for all version control.

I need to a way to have different mappings of the directory structure, so that the files can fit into each targeted development environment's existing structure. I want to be able to check changes in from these mapped directories, since we'll be doing active development on the library within a given platform's directory structure. For example, bringing a new platform up may expose errors in the library, and it's easiest to fix them in place, and commit the changes from that structure.

For example, one platform might have the following structure:

  • src/foo
  • src/foo/platform
  • src/alternate_name_for_bar
  • src/baz
  • include/foo
  • include/bar
  • include/baz
  • samples/foo
  • samples/foo/common

While another might be like this:

  • Lib/Blah/foo
  • Lib/Blah/foo/platform
  • Lib/Blah/bar
  • Lib/Blah/foo/baz (note baz as a subdir of foo instead of same level)
  • include/foo
  • include/bar
  • include/baz
  • Samples/foo
  • Samples/foo/common

And the repository:

  • src/foo
  • src/bar
  • src/baz
  • src/platform1 (maps to foo/platform on platform 1's source)
  • src/platform2 (maps to foo/platform on platform 2's source)
  • src/platform3 (maps to foo/platform on platform 3's source)
  • include/foo
  • include/bar
  • include/baz
  • samples/common
  • samples/platform1 (maps to samples/foo on platform 1)
  • samples/platform2 (maps to samples/foo on platform 2)
  • samples/platform3 (maps to samples/foo on platform 3)

I have flexibility in the repository's directory structure, but I'd like something that makes sense and is easy to maintain. I also want to keep everything in a single repository, since a changeset can potentially affect one of the header files in include, multiple files in src and multiple sample programs.

With Subversion, I could use svn:externals to do the directory mappings. The repository has all files in a root directory called master, and then additional root directories for each platform that use svn:externals to map files/directories from master to whatever layout is required for the given platform.

I am very new to git, but I have read about submodules and they don't开发者_运维知识库 seem to fit the bill, since they don't allow directory mapping and you can't commit a change that spans multiple submodules (AFAIK).

Most of the embedded development takes place on Windows, so symbolic links won't work for the directory mappings.

There's a chance I'm looking at this the wrong way, and that I need a repository for each platform that pulls the common code from another repository. But from what I've read on git submodules, it won't be possible to do the directory mapping.


I'd suggest submodules for the shared modules (subtrees) as soon as the versioning cycle is indepent enough from the rest of the repository.

Another idea to mention, IMHO, would be topic branches. Keep some platform specific tweaks in topic branches, so you can 'overlay' them on top of a central branch that is in development.

topgit is one tool I quite like to manage topic branches a bit more automated. Topgit has a rather steep learning curve in my experience, so you might want to shun it for the moment.

I'd certainly keep everything in one repo; If you must you can

  • avoid git submodules
  • avoid symlinks

and still have 'logically' linked subtrees by a modest amount of scripting:

See git read-tree, e.g.

git read-tree --prefix=externals/ origin/3rdparty:i386/externals
git read-tree --prefix=samples/ origin/samples

(note how origin/3rdparty:i386/externals is a direct reference to a subtree of a specific ref, such as detailed in man git-rev-spec)

As long as you keep externals/ and samples/ in .gitignore for the regular branches that contain such dynamically linked subtrees you'd not run in much trouble at all (treat them as readonly in their linked form, much like svn externals).


So I finally moved from Subversion to git, and per @peachykeen's comment to my question, I was able to use junction points for my directory mappings. I just created a small batch file that looped through pairs of links and targets and used rmdir to remove old links and mklink /j to create new ones.

@echo off

:: Expand variables at execution time rather than at parse time.
setlocal EnableDelayedExpansion

SET MAPPING=    ^
    include\foo:include\foo ^
    include\bar:include\bar ^
    include\baz:include\baz ^
    src\foo:Lib\Blah\foo    ^
    src\bar:Lib\Blah\bar    ^
    src\baz:Lib\Blah\baz    ^
    src\util:Lib\Blah\foo\util  ^
    src\platform:Lib\Blah\foo\platform  ^
    samples\platform:Samples\foo    ^
    samples\common:Samples\foo\common   ^
    test:Test\foo

set PLATFORM=..\..\
set DRIVER=..\

for %%M in (%MAPPING%) do (
  for /f "tokens=1,2 delims=:" %%a in ("%%M") do (
    set SRC=%%a
    set DST=%%b
    if exist %PLATFORM%!DST! rmdir %PLATFORM%!DST!
    mklink /j %PLATFORM%!DST! %DRIVER%!SRC!
  )
)

This could even work with the driver as a git submodule. It's just necessary to run the batch file once to set up the junctions.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜