Re: cvs2git conversion produces "spurious" commits in the history.

Michael Haggerty <[email protected]> Mon, 08 Oct 2012 05:47:04 +0200
Newsgroups gmane.comp.version-control.subversion.cvs2svn.devel
Message-ID <[email protected]>
On 10/08/2012 12:01 AM, Etan Reisner wrote:
> On Sat, Oct 6, 2012 at 2:08 AM, Michael Haggerty <[email protected]> wrote:
> <snip>
>> The result of the conversion looks like this:
>>
>>> $ git log --decorate --graph --all --oneline
>>> * 096ce16 (branch) Import from MAIN c
>>> * 082d2de This commit was manufactured by cvs2svn to create branch 'branch'.
>>> * deeed43 Update a
>>> | * fb9a0dc (HEAD, master) Add c
>>> |/
>>> * c841f5d Add a
>>
>> The effect that you are seeing is caused by a combination of CVS
>> recording too little information about the history and perhaps cvs2git
>> not being aggressive enough about throwing out redundant commits.
>>
>> There are two ways that the history of file c that is present in your
>> repository could have been generated:
>>
>> 1. Merge from HEAD (what you did):
>>
>>        cvs up -r branch
>>        cvs up -j 1.1 c
>>        cvs ci -m "Import from MAIN c"
>>
>> 2. Add branch tag explicitly, then "modify" c with no changes:
>>
>>        cvs tag -b branch c
>>        cvs up -r branch
>>        cvs ci -f -m "Import from MAIN c" c
> 
> As far as I'm aware (and as some quick testing seems to indicate) this
> will not generate the same RCS file as in my sample repo (or real
> repo). CVS will not generate an empty commit like that for a file that
> it knows has not been changed (that is that cvs ci will be a no-op).

If you use the "-f" option, as above, then cvs creates the commit anyway.

>> In this particular case it would be reasonable to merge the two commits
>> into a single one, moving your "Import from MAIN c" commit message onto
>> the commit that adds c to b (i.e., sacrificing the autogenerated commit
>> message, which is anyway misleading).
> 
> Merging the commits in that direction would generate the wrong history
> though and CVS knows the timestamp of the correct history (as oppposed
> to your suggested history above which doesn't contain that additional
> timestamp information). As far as the actual CVS history is involved
> in this case the generated commit here seems to be entirely spurious
> and erroneous.

I don't understand your point.

>> The real *practical* problem is that picking more cleverly between these
>> various scenarios requires global information about the CVS history of
>> all files, and that is very expensive to compute during the conversion.
>>  On the other hand, git has excellent tools for examining and modifying
>> the history *after* the conversion (see git-filter-branch(1)).  For 2git
>> conversions, I think it would be much easier to write a tool that
>> examines the post-commit git history looking for these kinds of commit
>> constellations and fixes them up using git tools, then bake the result
>> in using "git filter-branch" *before* publishing the converted repository.
> 
> I haven't investigated what would need to be done to use
> git-filter-branch to sort out these sorts of problems though that's
> certainly an avenue I should look into. That being said though, and as
> I indicated in my original email, I believe that given the duplicated
> content of these commits and the fact that the real commits are left
> intact (and that the git-dump.dat file contains the correct blob
> references for them) it should be possible for me to simply delete the
> generated commits from the dump file before import to get a correct
> history (and we started working on gathering the information necessary
> to run a verify across those timestamps to be sure we got things
> right).

While editing the git-dump.dat file is possible, it becomes cumbersome
in real-world situations when the file can be many GiB in size and when
manually finding the places that need "fixing up" becomes impractical.

> P.S. Where in cvs2svn is this sort of determination made? What logic
> is involved exactly? I've been having a difficult time sorting out
> where all the moving parts in this process are and how they interact.

There is a lot of information in doc/design-notes.txt about the
algorithms used.

Most of the intelligence for simplifying single-file histories happens
during FilterSymbolsPass in the class CVSFileItems.

The work of deducing the project-wide commits from all of the
single-file histories is done in the passes starting with
InitializeChangesetsPass.

Michael

-- 
Michael Haggerty
[email protected]
http://softwareswirl.blogspot.com/

------------------------------------------------------
http://cvs2svn.tigris.org/ds/viewMessage.do?dsForumId=1667&dsMessageId=3018242

To unsubscribe from this discussion, e-mail: [[email protected]].