Discussion:
Merge issue with deleted files
Cristian
2009-11-04 19:15:39 UTC
Permalink
I have been using CVS for quite a while and started doing merges back
about 4 years ago. Since, I have not run into any problems, till now
that is. I would appreciate any help on this.


Env: I am running CVS client and server 1.11.22 on Linux 2.6 Kernel.


I have run into this issue when merging from one branch onto another.
A file had been removed on branch B1 and modified on branch B2 with a
couple of revisions (irrelevant perhaps, we were doing some
refactoring).

Branch B2 is my target branch - so I am merging B1 into B2.

I have merged using two join commands so the common ancestor has been
passed to cvs as the first -j. To my surprise, the file got removed
from B2 branch by the merge, and was not flagged as a conflict - which
I would have thought should happen in this scenario.

# checked out B2
cvs -q up -dP -jB1_ROOT -jB1 -kk

Where B1_ROOT is rev 1.6 and B1 branch has been created off of
B1_ROOT. I have 1.6.36.1 on B1 which is marked as 'dead' and 1.6.8.2
in B2 -- we had two revisions on branch B2 since B1 was created at 1.6
(B1_ROOT).

When I noticed this, I have also tried using one -j essentially
passing the branch name which also corresponds to the latest revision
on the B2 branch. At the same time, in this particular case it would
have also been alright I believe to use only 1 -j since it was the
first merge from B1 to B2 so I would not have to worrry about merge
history and the like.

cvs -q up -dP -jB1 -kk

There is a message been spit out by CVS 'file XX has been modified,
but has been removed in revision B1 but the file is not been marked as
a conflict, its status is 'up-to-date'. I am not sure what to do in
the future about this because sometimes I do need to merge more than
one time from a branch, in which case I would need to use two -j and I
would run into the same issue.


Thanks,
Cristian
Risman, Mark
2009-11-05 17:12:56 UTC
Permalink
Cristian,

By using the update command with the two "j" arguments, you'll "merge
the differences between any two revisions into your working file."
(source: http://ximbiot.com/cvs/manual/cvs-1.11.22/cvs_5.html#SEC62)

The way I understand it, it's as if you were to look at the diff from
revision <first "j" argument> to revision <second "j" argument>, and
apply that to what's in your checkout. Kind of like how "cvs diff -e"
will create a set of commands that can be applied to the first revision
to produce the second.

In this case, the diff between those two revisions is "remove file". So
CVS applies a "remove file" to that file in your checkout. Would a
conflict be more desired in this case?

-----Original Message-----
From: info-cvs-bounces+mark.risman=***@nongnu.org
[mailto:info-cvs-bounces+mark.risman=***@nongnu.org] On Behalf Of
Cristian
Sent: Wednesday, November 04, 2009 2:16 PM
To: info-***@nongnu.org
Subject: Merge issue with deleted files

I have been using CVS for quite a while and started doing merges back
about 4 years ago. Since, I have not run into any problems, till now
that is. I would appreciate any help on this.


Env: I am running CVS client and server 1.11.22 on Linux 2.6 Kernel.


I have run into this issue when merging from one branch onto another.
A file had been removed on branch B1 and modified on branch B2 with a
couple of revisions (irrelevant perhaps, we were doing some
refactoring).

Branch B2 is my target branch - so I am merging B1 into B2.

I have merged using two join commands so the common ancestor has been
passed to cvs as the first -j. To my surprise, the file got removed
from B2 branch by the merge, and was not flagged as a conflict - which
I would have thought should happen in this scenario.

# checked out B2
cvs -q up -dP -jB1_ROOT -jB1 -kk

Where B1_ROOT is rev 1.6 and B1 branch has been created off of
B1_ROOT. I have 1.6.36.1 on B1 which is marked as 'dead' and 1.6.8.2
in B2 -- we had two revisions on branch B2 since B1 was created at 1.6
(B1_ROOT).

When I noticed this, I have also tried using one -j essentially
passing the branch name which also corresponds to the latest revision
on the B2 branch. At the same time, in this particular case it would
have also been alright I believe to use only 1 -j since it was the
first merge from B1 to B2 so I would not have to worrry about merge
history and the like.

cvs -q up -dP -jB1 -kk

There is a message been spit out by CVS 'file XX has been modified,
but has been removed in revision B1 but the file is not been marked as
a conflict, its status is 'up-to-date'. I am not sure what to do in
the future about this because sometimes I do need to merge more than
one time from a branch, in which case I would need to use two -j and I
would run into the same issue.


Thanks,
Cristian





**********************************************************

MLB.com: Where Baseball is Always On
Paul Sander
2009-11-05 21:08:09 UTC
Permalink
Christian describes a merge conflict: new revisions were created on
one branch, and the file was deleted on the other. This is definitely
a conflict because the new revisions might contain critical data
(though Christian says that in this particular case they are not).
CVS should present the user with a method of resolving the conflict by
asking the user whether or not to delete the file on the target
branch, and if the user declines deletion then CVS should treat the
conflict as an ordinary merge conflict in which the file deletion is
replaced by an empty file, letting the user edit the resulting file.

Now the hard part: Suppose the deletion was declined and the result
of the above merge is then merged back to the contributing branch.
Does CVS leave the file in its deleted state? Or does CVS resurrect
the file and keep the result of the prior merge? This time there is
no conflict, but there's also a good chance of getting incomplete
results requiring unusual manual intervention.
Post by Risman, Mark
Cristian,
By using the update command with the two "j" arguments, you'll "merge
the differences between any two revisions into your working file."
(source: http://ximbiot.com/cvs/manual/cvs-1.11.22/cvs_5.html#SEC62)
The way I understand it, it's as if you were to look at the diff from
revision <first "j" argument> to revision <second "j" argument>, and
apply that to what's in your checkout. Kind of like how "cvs diff -e"
will create a set of commands that can be applied to the first
revision
to produce the second.
In this case, the diff between those two revisions is "remove file". So
CVS applies a "remove file" to that file in your checkout. Would a
conflict be more desired in this case?
-----Original Message-----
Cristian
Sent: Wednesday, November 04, 2009 2:16 PM
Subject: Merge issue with deleted files
I have been using CVS for quite a while and started doing merges back
about 4 years ago. Since, I have not run into any problems, till now
that is. I would appreciate any help on this.
Env: I am running CVS client and server 1.11.22 on Linux 2.6 Kernel.
I have run into this issue when merging from one branch onto another.
A file had been removed on branch B1 and modified on branch B2 with a
couple of revisions (irrelevant perhaps, we were doing some
refactoring).
Branch B2 is my target branch - so I am merging B1 into B2.
I have merged using two join commands so the common ancestor has been
passed to cvs as the first -j. To my surprise, the file got removed
from B2 branch by the merge, and was not flagged as a conflict - which
I would have thought should happen in this scenario.
# checked out B2
cvs -q up -dP -jB1_ROOT -jB1 -kk
Where B1_ROOT is rev 1.6 and B1 branch has been created off of
B1_ROOT. I have 1.6.36.1 on B1 which is marked as 'dead' and 1.6.8.2
in B2 -- we had two revisions on branch B2 since B1 was created at 1.6
(B1_ROOT).
When I noticed this, I have also tried using one -j essentially
passing the branch name which also corresponds to the latest revision
on the B2 branch. At the same time, in this particular case it would
have also been alright I believe to use only 1 -j since it was the
first merge from B1 to B2 so I would not have to worrry about merge
history and the like.
cvs -q up -dP -jB1 -kk
There is a message been spit out by CVS 'file XX has been modified,
but has been removed in revision B1 but the file is not been marked as
a conflict, its status is 'up-to-date'. I am not sure what to do in
the future about this because sometimes I do need to merge more than
one time from a branch, in which case I would need to use two -j and I
would run into the same issue.
Thanks,
Cristian
**********************************************************
MLB.com: Where Baseball is Always On
Cristian
2009-11-06 19:53:28 UTC
Permalink
Thanks for your response Paul.
Christian describes a merge conflict:  new revisions were created on  
one branch, and the file was deleted on the other.  This is definitely  
a conflict because the new revisions might contain critical data  
(though Christian says that in this particular case they are not).  
CVS should present the user with a method of resolving the conflict by  
asking the user whether or not to delete the file on the target  
branch, and if the user declines deletion then CVS should treat the  
conflict as an ordinary merge conflict in which the file deletion is  
replaced by an empty file, letting the user edit the resulting file.
A conflict would have been my expectation in this particular case.
There was actually a big fuss about this in our group because we ended
up going to QA and a bunch of bugs were found until this was tracked
down. What happened is that a group of developers have worked on a
branch doing some refactoring which involved moving some stuff around
(took them almost 4 months) while the rest of the developers were
working on the 'regular' development branch totally unaware of what is
going on with regards to the refactoring. The idea was that when we
had everything merged back in they would get all of these changes done
in the development branch for which the directories/files have moved,
as conflicts, side by side with all of the other expected conflicts
that we get when we merge. At the time of the merge, I did not have
much in the way of details about the kind of work that was done.


As I mentioned before, what gets me is the different behaviour of CVS
with regards to using one -j vs two -j's.

For one -j, the file that underwent changes in the development branch
does not change status (up-to-date) but a message is given.
For two -j's the file that underwent changes in the development branch
gets removed, marked as "R" and no message is given.

Even if I was to use the one -j, with only a message given I don't
know how I could have found it. When I merge, at the size of our
product, on a medium size merge I probably get over 20.000 lines of
output - so unless I know to specifically look for this message, I
would completelly missed what is happening and instead of the files
been removed, I would have ended up with files that are no longer in
play.

For the two -j's, stil shaking my head.

I would really think that a conflict would be the way to go. I can
understand some would say that technically this is not a conflict. No
problem, then perhaps a different state? Anything that one can query
the workspace and be able to appropriatelly deal with this situation.
But I believe a different state is not that easy to implement.
Now the hard part:  Suppose the deletion was declined and the result  
of the above merge is then merged back to the contributing branch.  
Does CVS leave the file in its deleted state?  Or does CVS resurrect  
the file and keep the result of the prior merge?  This time there is  
no conflict, but there's also a good chance of getting incomplete  
results requiring unusual manual intervention.
I would think that if the deletion is declined, then CVS should keep
the result prior to the merge. That would make sense to me, but I
might be missing something.


Thanks,
Cristian
Cristian
2009-11-06 19:28:42 UTC
Permalink
Thanks for your reply Mark.
Post by Risman, Mark
By using the update command with the two "j" arguments, you'll "merge
the differences between any two revisions into your working file."
(source:http://ximbiot.com/cvs/manual/cvs-1.11.22/cvs_5.html#SEC62)
The way I understand it, it's as if you were to look at the diff from
revision <first "j" argument> to revision <second "j" argument>, and
apply that to what's in your checkout. Kind of like how "cvs diff -e"
will create a set of commands that can be applied to the first revision
to produce the second.
Right, that is my understanding also. In regards to using one or two -
j's - I have always felt that I need to have an explicit branch root
tag when I create a branch and since I have that I have always used
two -j's when I merge even if that was the first merge and I could
have used only one -j and have the root of the branch figured out by
cvs.

ie. File with common ancestor at 1.4 with rev 1.4.2.3 on branch A and
rev 1.4.4.2 on branch B. If I use only one -j (name of branch) then
cvs would figure out for me that it needs rev 1.4 as the common
ancestor. If I use two -j's then I am passing 1.4 explicitly as the
root tag of branch A, essentially the same thing. That is my
understanding anyway.

For this reason, I am very surprised not only at the fact that the
changes on the target branch were basically wiped out, but also to
find a different behavior between using one -j and two -j's.
Post by Risman, Mark
In this case, the diff between those two revisions is "remove file". So
CVS applies a "remove file" to that file in your checkout. Would a
conflict be more desired in this case?
Instinctively I would have thought that would be a conflict. I mean,
if I removed a file on one branch and done no revisions on the target
branch, then sure, I expect the file to be removed by the merge, no
question. But when the file on the target branch had changes in it
since the start of the dev branch, I would have never thought that it
would result essentially in a removal with no message. Very surprised
by these findings.


Thanks,
Cristian
Jim Hyslop
2009-11-07 03:39:08 UTC
Permalink
Post by Cristian
Thanks for your reply Mark.
[...]
Post by Cristian
Post by Risman, Mark
The way I understand it, it's as if you were to look at the diff from
revision <first "j" argument> to revision <second "j" argument>, and
apply that to what's in your checkout.
That is precisely how it works.
Post by Cristian
Instinctively I would have thought that would be a conflict.
You need to retrain your instincts :-)

As Mark pointed out, the difference between the two versions was "remove
the file." The difference - "remove the file" - was then applied to the
working directory. There is no conflict to report.
Post by Cristian
There is a message been spit out by CVS 'file XX has been modified,
but has been removed in revision B1'
I think what you have really learned is: warnings are issued for a
reason. Pay attention to them!

- --
Jim Hyslop
Dreampossible: Better software. Simply. http://www.dreampossible.ca
Consulting * Mentoring * Training in
C/C++ * OOD * SW Development & Practices * Version Management
Larry Jones
2009-11-07 16:14:16 UTC
Permalink
Post by Cristian
As I mentioned before, what gets me is the different behaviour of CVS
with regards to using one -j vs two -j's.
That's completely intentional. One -j merges two branches with a common
ancestor, so CVS considers all the changes along both branches. Two
-j's applies one set of changes to a specific revision -- there's only
one set of changes, so there's nothing to conflict. Remember: with two
-j's, the set of changes can be completely disjoint from the revision
you're applying them to; what changes would you want CVS to consider?
In your case, there just happens to be an obvious choice, but what if
you were applying the changes between 1.3.6.5 and 1.3.6.7 to 1.14.8.7 --
would you really want to go back to the common ancestor at 1.3?
--
Larry Jones

When I want an editorial, I'll ASK for it! -- Calvin
Loading...