Git::FastExport::Stitch - Stitch together multiple git fast-export streams
version 0.108
# create a new stitch object my $export = Git::FastExport::Stitch->new(); # stitch in several git fast-export streams # a git directory $export->stitch( A => 'A' ); # a Git::Repository object $export->stitch( Git::Repository->new( work_tree => 'B' ) => 'B' ); # output the stitched stream while ( my $block = $export->next_block() ) { print $block->as_string(); }
Git::FastExport::Stich is a module that "stitches" together several git fast-export streams. This module is the core of the git-stitch-repo utility.
Git::FastExport::Stitch objects can be used as Git::FastExport, since they support the same inteface for the next_block() method.
next_block()
Git::FastExport::Stitch supports the following methods:
my $export = Git::FastExport::Stitch->new( \%option );
Create a new Git::FastExport::Stitch object.
The options hash defines options that will be used during the creation of the stitched repository.
The select option defines the selection algorithm to be used when the last alien child algorithm reaches a branch point. Valid values are: first, last and random. The default value is last.
first
last
random
See "STITCHING ALGORITHM" for details about what these options really mean.
The remaining parameters (if any) are taken to be parameters (passed by pairs) to the stitch() method.
stitch()
# add the repository to the list of repositories to stitch $export->stitch( $repo => $dir );
Add the given $repo to the list of repositories to stitch in.
$repo
$repo can be either a directory, or a Git::Repository object (both will be used to instantiate a Git::FastExport object).
The optional $dir parameter will be used as the relative directory under which the trees of the source repository will be stored in the stitched repository.
$dir
The basename of the $repo repository (mapped to ASCII without the .git suffix) is used as the internal name for $repo. This internal name is used as a suffix on refs copied from $repo. When there's a collision, an extra suffix (-A, -B, etc.) is added.
-A
-B
my $block = $export->next_block();
Return the next block of the stitched repository, as a Git::FastExport::Block object.
Return nothing at the end of stream.
Git::FastExport::Stitch processes the input commits in --date-order fashion, and builds the new graph by attaching the new commit to another commit of the graph being constructed. It starts from the "original" parents of the node, and tries do follow the graph as far as possible.
When a commit has several suitable child commits, it needs to make a selection. There are currently three selection algorithms:
Pick the last child commit, i.e. the most recent one. This is the default.
Pick the first child commit, i.e. the oldest one.
Pick a random child.
Imagine we have two repositories A and B that we want to stitch into a repository C so that all the files from A are in subdirectory A and all the files from B are in subdirectory B.
Note: in the following ASCII art graphs, horizontal order is chronological.
Repository A:
,topic ,master ,-A3------A5--A6 / / A1--A2------A4'
Branch master points to A6 and branch topic points to A3.
Repository B:
,topic ,master ,-B3------B5------B7--B8 / / B1--B2------B4------B6'
Branch master points to B8 and branch topic points to B5.
The RESULT repository should preserve chronology, commit relationships and branches as much as possible, while giving the impression that the directories A/ & B/ did live side-by-side all the time.
Assuming additional timestamps not shown on the above graphs (the commit order is A1, B1, A2, B2, A3, A4, B3, B4, A5, B5, B6, B7, B8, A6), Git::FastExport::Stitch will produce a git-fast-import stream that will create the following history, depending on the value of --select:
,topic-B ,-B3----------B5----. / \ ,master-B A1--B1--A2--B2------A4------B4--A5------B6--B7---B8--A6 \ / `master-A `-A3------------' `topic-A
,---------B4----------B6-. / \ ,master-B A1--B1--A2--B2--A3------B3------A5--B5------B7---B8--A6 \ `topic-A / `topic-B `master-A `-----A4--------'
In this example, there are only two places where the selection process is triggered, and there are only two items to choose from each time. Therefore the random selection algorithm will produce 4 possible different results.
In addition to the results shown above (last+last and first+first), we can also obtain the two following graphs:
last+last
first+first
first+last:
first+last
,topic-A ,master-B A1--B1--A2--B2--A3--------------A5------B6--B7---B8--A6 \ / / `master-A `-----A4------B4' B5----' \ / `topic-B `-B3--------'
last+first:
last+first
,master-B A1--B1--A2--B2------A4------B4----------B6--B7---B8--A6 \ \ / `master-A \ `-B3------A5--B5----' \ / `topic-B A3------------' `topic-A
Any mathematician will tell you there are many many ways to stitch two DAG together. This programs tries very hard not to create inconsistent history with regard to each input repository.
The algorithm used by Git::FastExport::Stitch enforces the following rules when building the resulting repository:
a commit is attached as far as possible in the DAG, starting from the original parent
a commit is only attached to another commit in the resulting repository that has exactly the same ancestors list as the original parent commits.
when there are several valid branches to follow when trying to find a commit to attach to, use the selection process (last or first commit (at the time of attachement), or random commit)
branches starting from the same commit in a source repository will start from the same commit in the resulting repository (this particular rule can be lifted: adding an option for this in on the TODO list)
The current implementation can probably be improved, and more options added. I'm very interested in test repositories that do not give the expected results.
To run the stitching algorithm, Git::FastExport::Stitch makes use of several internal methods. These are not part of the public interface of the module, and are detailed below for those interested in the algorithm itself.
$self->_translate_block( $repo );
Given a repo key in the internal structure listing all the repositories to stitch together, this method "translates" the current block using the references (marks) of the resulting repository.
To ease debugging, the translated mark count starts at 1_000_000.
1_000_000
my $commit = $self->_last_alien_child( $node, $ref, $parents )
Given a node, its ref name (actually, the reference given on the commit line of the fast-export) and a structure describing its lineage over the various source repositories, find a suitable commit to which attach it.
commit
This method is the heart of the stitching algorithm.
git-stitch-repo
Philippe Bruhat (BooK) <book@cpan.org>
Copyright 2008-2016 Philippe Bruhat (BooK), All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
To install Git::FastExport, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Git::FastExport
CPAN shell
perl -MCPAN -e shell install Git::FastExport
For more information on module installation, please visit the detailed CPAN module installation guide.