[darcs-devel] hunk moves as a new kind of prim patch
Ben Franksen
ben.franksen at online.de
Thu Feb 15 21:04:42 UTC 2018
Am 15.02.2018 um 07:48 schrieb Ganesh Sittampalam:
> On 14/02/2018 23:34, Ben Franksen wrote:
>
>> If we had primitive "hunk move" patches we could avoid conflicts in many
>> cases.
>
> I'd love to have this, and spent a while thinking about it some years
> ago. I think the commute rules will be quite tricky to get right, as
> there are lots of cases, e.g. overlaps between either source or
> destination of the move. Getting the boundary conditions (do touching
> patches commute or not) is also quite tricky even for hunk patches, but
> we can err on the side of being conservative.
Yes, that was my thought, too. And yes, the side conditions are a bit
trickier than I thought. More on that below.
BTW:
I have a question regarding the existing hunk commutation behavior. When
I experimented with the example I sent, I noticed something strange:
Keeping with the notation in my original message, if i have
A: abc -> acb
i.e. move "b" to the end, versus
B: abc -> abd
i.e. change the third line to "d", then A and B currently conflict. I
wonder why this is the case. To further test this, I have split A into
the two hunks (one that removes "b" and one that re-adds it) and
recorded them separately. I already get the conflict for the first of
the two patches, i.e. the one that removes the second line (abc -> ac).
I don't see why there is a conflict here. Could/should we relax the
rules? What could go wrong?
> The way I was thinking about the commute rules before was to break the
> move down into a "cut" and a "paste" operation - I don't think those
> should be actual primitive patch types, but it helps to think about them
> that way when working out the rules.
Exactly what I am doing right now. I have this code now:
{-
The fields of HunkMove are:
- file name where data is removed
- line number where data is removed
- file name where data is inserted
- line number where data is inserted
- the data
The semantics is left-to-right, i.e. first remove data, then insert
data. Thus, in case of a hunk move inside the same file, the line number
where the data is inserted is the line number *after* the data has been
removed. IOW
apply (HunkMove fo lo fn ln h)
=
apply (FP fo (Hunk lo h []) :> FP fn (Hunk ln [] h))
=
apply (FP fo (Hunk lo h [])) >> apply (FP fn (Hunk ln [] h))
This makes for very simple instances Apply and Invert.
-}
data HunkMove = HM !FileName !Int !FileName !Int [B.ByteString]
deriving (Eq, Ord)
The instance Invert simply swaps (fo,lo) with (fn,ln).
For commutes involving HunkMoves we can allow everything that is allowed
now, in particular, for the three cases HunkMove :> Hunk, Hunk :>
HunkMove, and HunkMove :> HunkMove we can copy the (good) cases implied
by splitting HunkMoves into two (semantically equivalent) Hunks.
In addition, commutation also succeeds whenever the add-part of the Hunk
on the left hand side is contained in the remove-part of the HunkMove.
Analogously, whenever the remove-part of a hunk on the right hand side
is fully contained in the add-part of the HunkMove on the left hand side.
> I think we'd definitely want moving between files as you mention, that
> means you can really express code refactorings properly.
Thanks for the encouragement. I am on it...
Cheers
Ben
More information about the darcs-devel
mailing list