|
From: Daniel J S. <dan...@ie...> - 2017-10-31 04:24:51
|
On 10/30/2017 05:52 PM, Hans-Bernhard Bröker wrote:
> Am 30.10.2017 um 20:30 schrieb Daniel J Sebald:
>
>> I'd sort of like to put effort into the right place. I've cloned the
>> cvs-fast-export utility and I'm willing to help on matters, so if its
>> possible I wonder if we could enhance the merging aspect of that utility.
>
> I rather doubt any good will come from that. Nobody understands that
> utility anywhere near well enough to be able to modify it on short
> notice without risking total break-down. At this point it is,
> essentially, magic.
It doesn't look like a very big program.
>> Yes, there is a bit of ambiguity in merges with CVS, it just isn't
>> 100% accurate to identify exactly what the programmer had checked out
>> when compiling and subsequently did a checkin.
>
> Not really, because there _are_ no recorded merges in CVS. If merges
> happen, they do so in somebody's working copy. To the repository, they
> only ever appear as check-ins, without any indication whether the new
> content was created by some kind of merge, or by just writing it manually.
I didn't state that right; I should have said "implied merges" or
"psuedo-merges", i.e., the merges placed in the git translation by the
conversion tool. And the way something like cvs2git has an implied
history for constructing those merges comes from the fact Lars placed
what looks like three dozen or more tags in the work. Without all those
tags, it would be as you described below, simply a trail of numbers.
>> There might be some ambiguity about the state of other files at this
>> point, but I would say simply recall the BETA_344_989422 state from
>> CVS and call that the state for the merge and generate all git diffs
>> accordingly, perhaps that's not the exact methodology.
>
> That won't work at all. The primary conflict is that CVS has individual
> branch structures for every member file, whereas git branches the entire
> repository. Those two concepts don't mix and match. BETA_344_989422
> may be the right join point for this particular file, but that's most
> likely the _only_ file for which that's the case.
It's not. I believe there are several files that fall in that same
category. I can search for them, to verify, but that's a lot of work.
But in terms of principle, generally BETA_344_989422 can appear in
multiple files in the same way. I sent screenshots of what cvs2git
produces for merges, and it seems to produce a good job of matching CVS
updates to various versions. Here are the sorts of statements cvs2git
is making:
"This commit was generated by cvs2svn to compensate for changes in r48,
which included commits to RCS files with non-trunk default branches."
BETA_344_989422:1.1.1.2 (this tag is in the trunk, but it's
referencing a version that is in a branch different than the trunk)
BETA_344:1.1.1.2 (this tag is in the branch)
BETA_343_980416:1.1.1.1
> Basically every
> single tag ever made in CVS can contain one or more file joins from the
> vendor branch onto the trunk. Some are still waiting to happen.
That's correct, one or more. And in every one of those merges back to
the trunk (in cvs2git) there are probably a half dozen files that have
that same pattern of being referenced by BETA_344_989422. It's a
subgroup of at least all these files I listed previously:
amiga.c
Copyright
ctrl87.c
ctrl87.h
demo/gnuplot.rot
docs/gpcard.tex
docs/old/ChangeLog.old [This is RCSid diff, does not count]
docs/old/makefile.r [Ditto]
docs/old/README.3p5 [Ditto]
fnproto.h
intergra.x11
os9.c
win/wgnuplib.c
win/wprinter.c
win/wresourc.h
and then there are a bunch of ancillary changes that are being made to
many other files that keep the psuedo-merge in sync.
> Normal CVS repositories would have every single file starting off at
> 1.1. I.e. the first tag would be on 1.1 revisions of every file, and
> all development would start from there. The conversion tools have no
> problem at all with this set-up.
>
> But our repository was started by a "cvs import", and received some
> further imports after that, and that changes everything. It means that
> all our original files started at revision 1.1.1.1, and progressed along
> that 1.1.1.* branch, until they were first modified. None of them ever
> got a tag on it 1.1 revision --- 1.1. was really never used for anything.
>
> Every time a file that was on the vendor branch until that point (and
> remember, for some files that still hasn't happened today!) is checked
> in, that particular file is essentially merged over from the vendor
> branch onto the trunk --- but in the archive this merge appears as an
> ordinary check-in of a revision 1.2.
>
> E.g. even though in a RCS revision tree, it appears like this:
>
> 1.1 --*---> 1.2
> \
> +-> 1.1.1.1 --> 1.1.1.2
>
> the real sequence of active revisions for gnuplot.rot is:
>
> 1.1.1.1 --> 1.1.1.2 --> 1.2
>
> Other files have different sequences, and different points in time at
> which they made their transition 1.1.1.1 --> 1.1.1.2, or 1.1.1.{n} -->
> 1.2. Some even have branches inside the vendor branch (1.1.1.2.2.1)
Correct, but the psuedo-merges don't really care about all the different
times, just all the files associated with a particular tag, in this case
BETA_344_989422. I'm not sure, but I think cvs2git in this case makes a
rough estimate of the time which it assigns to the merge, like maybe
halfway between the latest age of any file and the next modification.
When a psuedo-merge took place exactly isn't important, just that it
fits sequentially in the proper location (i.e., it must have happened
between A and B is the important part).
> The vendor branch may best be grafted into the trunk _before_ the 1.1
> initial import, and replace that entirely. I.e. we might imagine that
> the above sequence was transformed into
>
> 1.0 --> 1.1 --> 1.2
Yes, there are multiple ways to imagine this, but I think from a
conversion tool's standpoint it has to pick the scenario, e.g., we're
going to assume this is a master branch and then follow all these
branches and merges according to the tags. It's similar to what I said
early on that even with git, once the heads of branches are merged, it's
sort of difficult to figure out in hindsight which particular branch was
associated with which head at the time.
> Files with more stuff going on in their vendor branch would have to dip
> into negative numbers, i.e.
>
> 1.1.1.1 --> 1.1.1.2 +-> 1.1.1.3 --> 1.1.1.4 --> 1.2 ...
> |
> +-> 1.1.1.2.2.1
>
> would (imaginatively) turn into
>
> 1.(-2) --> 1.(-1) +-> 1.0 ------> 1.1 ------> 1.2 ...
> |
> +-> 1.(-1).2.1
>
> Realistically all the revision numbers in the entire archive would have
> to be shifted up such that the chain really does start at 1.1:
>
> 1.1 -----> 1.2 --*---> 1.3 ------> 1.4 ------> 1.5 ...
> \
> +-> 1.2.2.1
>
> Unfortunately, the way RCS ,v files are organized, this shift can only
> be performed by parsing and re-encoding every revision on the vendor
> branch. (The direction the diffs are recorded is from the head all the
> way down to 1.1, and from there _up_ along the vendor branch). And
> because of the way CVS uses RCS ,v files, every one of them has to be
> transformed individually.
Maybe that is what cvs2git is doing. As I said, it takes 45 minutes.
But gosh the tree-structure and tags of cvs-fast-export matches cvs2git
so well. I think it is a simple matter of cvs-fast-export not
recognizing it has to do a merge in those half dozen locations due to a
cross-branch reference to a version number. If reposurgeon could make
those connections, it would be nice, but I don't think reposurgeon works
that way, just rebasing.
> _That_ is the transformation that needs to be done in order for
> conversion tools not to have any problems with the vendor branch. And
> because the transformation differs for every RCS archive, it has to be
> done either directly on the CVS repository, or the importer has to
> pretend it had happened that way.
>
> Let me reiterate: to the best of my understanding, no process working on
> an already converted git repository has any realistic chance to perform
> this operation correctly. It has to be done on the CVS import side.
But I said that. cvs-fast-export has access to all that original
information; it's the place this sort of thing should be addressed.
I suggest trying cvs2git and then explore the various changesets for the
repository, see if it makes sense, and keep in mind this idea that the
abundance of tags from Lars is the added information that's giving these
merges an implied structure.
I'm willing to help, I identified all the branch points and agree with
what cvs2git is producing in terms of psuedo-merges, tested against CVS
etc.. I'm willing to look into cvs-fast-export (as I see it, git-wise,
merges and branches are very similar except the branch case is like
having one of the bases of a merge be empty, so there might not need to
be too much code-writing). But I didn't make the call on
cvs-fast-export, so I think the decision of what to do here is up to
someone else at this point.
Dan
|