No way to switch off Bazaar's automatic conflict resolution

Bug #263302 reported by Jonny Dee
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Bazaar
Confirmed
Wishlist
Unassigned

Bug Description

I've figured out that Bazaar does not allow to switch off automatic conflict resolution. I think there should be something like a dumb conflict resolution strategy which just marks all differences as conflicts instead of trying to resolve as much conflicts as possible automatically.

Here is my use case:
I am working on two branches A and B which contain nearly the same contents. Some source files, however, differ in some places. Sometimes I work on branch A and want to merge my changes into B, sometimes I do it vice versa. But while doing this, I would like to maintain some of the mentioned differences. Think of a configuration file in A and in B, for example, which contain common and different information in each branch. Now when I change the common part in, let's say A, then I would like to merge in only(!) the common part into B's configuration file. Using Bazaar's merge command would now merge in all contents of A into B and, hence, overwrite the branch specific part of B. Thus, what I need is to do a manual merge using, for example an external merge program like kdiff3. The 'extmerge' plugin is a good tool for this, but it requires to have all differences to be marked as conflicts.

In short, Bazaar tries to be as intelligent as possible in resolving conflicts (which it does indeed very good) but it should also allow to behave as dumb as possible.

Best regards,
Jonny

Jonny Dee (jonny.dee)
description: updated
description: updated
Jonny Dee (jonny.dee)
description: updated
Revision history for this message
James Westby (james-w) wrote :

Hi Jonny,

I'm not sure I understand your use case fully. In the example you present
you appear to have a file with a modification specific to A, and then merging
B overwrites this modification, is that what you are saying?

I don't understand why this would happen, as if both A and B had modified
the same area then it would cause a conflict, rather than overwriting it.

Or is it that A doesn't actually modify the file, it just doesn't want B's change?
The usual way to do this would be to "revert" out the changes, either using
the "revert" command or editing. I can see that it wouldn't be easy to do this
at the hunk level, as "revert" only works at the file level.

Is your request to have conflict regions for every change made by B, regardless
of whether A has modified that area?

Thanks,

James

Changed in bzr:
status: New → Incomplete
Jonny Dee (jonny.dee)
description: updated
Revision history for this message
John A Meinel (jameinel) wrote :

I believe what he wants is "bzr merge --merge-type=dumb" which says that if texts A and B differ, and one is not a child of the other, conflict.

Honestly, this could be done in a plugin, which just registers the merge algorithm. Something like:

from bzrlib import errors, merge
class DummyMerger(merge.Merge3Merger):

  def text_merge(self, file_id, trans_id):
    raise errors.BinaryFile()

merge.get_merge_type_registry().register('dummy', DummyMerger, "merger which refuses to do text merges")

(put the above text in a dummy_merger.py file and put it into ~/.bazaar/plugins)

Then you should be able to do "bzr merge --dummy". It will use the logic that:

1) Compare OTHER to BASE for file X, if OTHER == BASE, do nothing
2) Compare THIS to BASE, if THIS == BASE, then take the value from OTHER
3) If both THIS != BASE and OTHER != BASE, conflict

Which is, I think, what he wants.

Revision history for this message
John A Meinel (jameinel) wrote :

I should also mention, that if you have this "plugin" installed, you can do: "bzr merge" as normal, and then for the specific files you want, you can do "bzr remerge --dummy config_file".

Revision history for this message
Jonny Dee (jonny.dee) wrote :

Hi James,

thank you for taking the time to think about my problem.

> Or is it that A doesn't actually modify the file, it just doesn't want B's change?
> The usual way to do this would be to "revert" out the changes, either using
> the "revert" command or editing. I can see that it wouldn't be easy to do this
> at the hunk level, as "revert" only works at the file level.

I think with "hunk level" you got my idea. But just to be sure I would like to give you an example:

Configuration file in Branch A:
---------------------------------------
<configuration>
    <property name="Version" value="1.0" />
    <property name="home-path" value="C:\Documents and Settings\foo" />
</configuration>

Configuration file in Branch B:
---------------------------------------
<configuration>
    <property name="Version" value="1.0" />
    <property name="home-path" value="/home/foo" />
</configuration>

Now, let's say I change "Version" in branch A to "2.0" and "home-path" to "bar" and commit the new configuration. Now my intent is to merge into branch B only the change of the "Version" property. Doing a "bzr merge PATH_TO_BRANCH_A" would now merge all(!) changes from A into B. Thus, the configuration file of Branch B would look like:

New configuration file in Branch B:
---------------------------------------
<configuration>
    <property name="Version" value="2.0" />
    <property name="home-path" value="C:\Documents and Settings\bar" />
</configuration>

But this is how it should look like:

New configuration file (like it is supposed to be) in Branch B:
---------------------------------------
<configuration>
    <property name="Version" value="2.0" />
    <property name="home-path" value="/home/foo" />
</configuration>

This is a case which cannot be resolved automatically, because Bazaar dosen't know exactly what "hunks" I want to retain. In this case I would like to be able to tell Bazaar to do no automatic merging at all. Instead, it should mark it as a conflict and create corresponding conflict files:

configuration.xml.BASE
configuration.xml.THIS (from branch B)
configuration.xml.OTHER (from branch A)

Now I can manually merge only some parts of A's config file into B using "extmerge" plugin, for example.

Please keep in mind that this is a very simple example. I have to deal with much bigger files and many parts that need to be retained for each branch separately. At the moment, I end up with a full copy of A's config file in B and I need to somehow get access to the previous version of B's config file in order to revert the parts I didn't want to be changed.

I hope I could make clear now what my problem is. Please feel free to ask me if my explanations are still a bit vague.

BTW, don't you think it would be a good idea to have a possibility to switch off automatic merging (regardless of my specific problem)?

Cheers,
Jonny

Revision history for this message
Jonny Dee (jonny.dee) wrote :

Hi John,

this is exactly what I've been looking for :)

I will try your suggestion and if it works (I'm sure it will) then I will push a corresponding plugin branch to Launchpad. (Though I think such a feature should finally end up in Bazaar itself. So maybe we could get rid of the "Incomplete" state again?).

Thank you very much for your help.

Best regards,
Jonny

Revision history for this message
James Westby (james-w) wrote :

Hi Jonny,

I'm not sure that John's suggested plugin is what you want, as in the
example you just gave you wouldn't trigger the code path, as
THIS==BASE, meaning it just takes the "OTHER" value.

It would be possible to write a merge type that did do what you want
though.

A couple more suggestions:

  * I think Robert implemented merge -i, which would allow you to
     select hunks at merge time. Something like revert -i would also
     help you.

  * You could write a plugin that allowed you to do the same as extmerge
     when the files weren't conflicted.

I don't really see a benefit to the merge strategy you outline, but I do
see that being able to revert particular hunks would be useful, so I'm not
sure if you really want the merge type that you specify, or whether this
is just a way that you can get extmerge to help you out.

Thanks,

James

Changed in bzr:
importance: Undecided → Wishlist
status: Incomplete → New
Revision history for this message
Jonny Dee (jonny.dee) wrote :

Hi James,

thank you very much for your quick answer.

> I'm not sure that John's suggested plugin is what you want, as in the
> example you just gave you wouldn't trigger the code path, as
> THIS==BASE, meaning it just takes the "OTHER" value.

Maybe you are right, John's suggested solution does indeed not trigger the code path in my given example. But as far as I understand it, the next time, when THIS and OTHER differ (which they do when they are committed with different content), a conflict will occur and the corresponding BASE, THIS, OTHER files are created. I think this behaviour will save me a lot of time.

> * I think Robert implemented merge -i, which would allow you to
> select hunks at merge time. Something like revert -i would also
> help you.

I've thought about the interactive version of merge but I like UI tools and as far as I know 'merge -i' does not invoke external diff tools (please correct me if I'm wrong).

> I don't really see a benefit to the merge strategy you outline, but I do
> see that being able to revert particular hunks would be useful, so I'm not
> sure if you really want the merge type that you specify, or whether this
> is just a way that you can get extmerge to help you out.

Well, at least I see a benefit of having such a feature. It saves me a lot of time, because now I can easily get the files for a three way merge. Using extmerge is just one solution, using kdiff3 on the files directly is another one -- which was my very first intent. Anyway, I have created a new project on launchpad which hosts John's solution (bzr-dumb-merge). Maybe someone else also needs such a functionality.

Very best regards and many thanks for your comments :)
Jonny

Revision history for this message
James Westby (james-w) wrote : Re: [Bug 263302] Re: No way to switch off Bazaar's automatic conflict resolution

On Sun, 2008-08-31 at 20:52 +0000, Jonny Dee wrote:
> Maybe you are right, John's suggested solution does indeed not trigger
> the code path in my given example. But as far as I understand it, the
> next time, when THIS and OTHER differ (which they do when they are
> committed with different content), a conflict will occur and the
> corresponding BASE, THIS, OTHER files are created. I think this
> behaviour will save me a lot of time.

I'm glad it will help you.

> I've thought about the interactive version of merge but I like UI tools
> and as far as I know 'merge -i' does not invoke external diff tools
> (please correct me if I'm wrong).

I don't think it does.

I'm not moving this bug to confirmed, as I either don't see the utility
of the feature you requested, and we haven't determined another feature
that would satisfy your needs with general utility. I'm happy for
anyone else to confirm this issue if they disagree.

Thanks,

James

Revision history for this message
John A Meinel (jameinel) wrote :

So, it would be possible to write an alternative form that did:

If OTHER != BASE => conflict

I didn't think that was strictly helpful here. Mostly, I think Jonny wants a way to avoid clean merges where both sides have modified the file. So say you had (pretend spaces are newlines):

 A B C

One side does

 A D B C

And the other does

 A B E C

The normal merge algorithm will treat that as non-conflicting, because it can cleanly write

 A D B E C

Without anything touching the other change.

In Jonny's case, he wants to invoke a graphical merge tool, but it requires having the BASE, THIS, OTHER files around. I could see a couple things:

1) The plugin I outlined, which uses our "binary" file conflict resolution, aka if both sides changed, conflict.
2) An algorithm that conflicts if OTHER != BASE. This basically causes a conflict in anything that OTHER changed. This could be useful with "bzr remerge" and extmerge, since it forces the gui to consider *all* files, not just the ones that couldn't be merged with 3-way.
3) A command to just dump the THIS, OTHER, and BASE files for any file that you chose.

Revision history for this message
Jonny Dee (jonny.dee) wrote :

Hi James, hi John,

I really appreciate your great support, thanks again :)

James, I understand that you don't see any benefit in the requested behaviour. Having it as a plugin is something I am totally comfortable with. And if you feel like the requested functionality is not worth a feature request please feel free to remove my bug from the wish list.

John, you are right. Your given example describes a case where I would like Bazaar to let me resolve the conflict:

> If OTHER != BASE => conflict

With other words, the functionality I would like to have is:

Every time Bazaar would merge changes from another branch into some specific file(s) I would like to be able to play the "man-in-the-loop". It's basically just switching off file merging. Instead of modifying the file automatically create a conflict.

I thought it should be no problem to switch off automatic merging algorithms, because for me it just looks like doing less than normal. Instead of a routine that does: "Oh, I detected a change, so I need to do some intelligent merging" it should do: "Oh, I detected a change, but, as was was told by a command line parameter, I am not intelligent enough to do merging, so I will not even try and create a conflict to let a human resolve it himself."

Regarding your three suggestions:
1) Is a good first approach which helps me in most cases, I think.
2) Seems to be what I've been thinking of.
3) Would also be a good solution, because my problem is that after doing a merge I a cannot easily access these three files. But, to me, it somehow feels like a workaround. On the other hand, it might be helpful for some other analysis purposes, too.

Thanks again for you attention,
Jonny

Revision history for this message
John A Meinel (jameinel) wrote :

So as I see it, we could add 2 new flags. One for "if you have to do any textual merging, conflict" and one for "conflict on every content change". They seem easy enough to implement and maintain. The only question is whether it would actually be more confusing for users to see them when looking at "bzr help merge".

Changed in bzr:
status: New → Triaged
Revision history for this message
Jonny Dee (jonny.dee) wrote :

> So as I see it, we could add 2 new flags. One for "if you have to do any textual merging, conflict" and one for
> "conflict on every content change". They seem easy enough to implement and maintain.

That would be really really really great :)

> The only question is whether it would actually be more confusing for users to see them when looking at
> "bzr help merge".

Well, it's hard to say whether other people might be confused by these additional options. But if you ask me, I'd say: I don't think so. Because there is also a good place where these options could be mentioned. Look at this section from the help message:

  [...]
  Merge will do its best to combine the changes in two branches, but there
  are some kinds of problems only a human can fix. When it encounters those,
  it will mark a conflict. A conflict means that you need to fix something,
  before you should commit.

I think here one could also mention that there is a way to enforce the creation of conflicts even if Bazaar thinks it could merge files, because in some cases only a human can fix a conflict, in spite of the fact, that a merge algorithm is able to do a merge without intervention.

Regards,
Jonny

Revision history for this message
Chris Hossack (hossa1c) wrote :

hi,
I'm a complete bzr newbie, but I also have the same problem as Jonny. I have a two branches that are similar, but contain important differences that I don't want to lose.

So when I perform a merge I want to visually accept/change/reject all changes.

I've tried creating a "C:\Program Files\Bazaar\plugins\dummy_merger.py", but when I use the commands

 bzr merge --merge-type=dumb
or
 bzr --dumb

I get "bzr: ERROR: Bad value "dumb" for option "merge-type"." or "bzr: ERROR: unknown command "--dumb".

Can you tell me what I'm doing wrong, or has bzr 1.15 evolved to add this feature automatically yet?

cheers

Chris

Revision history for this message
Jonny Dee (jonny.dee) wrote :

Hi Chris,

I have created a Bazaar project on Launchpad, which hosts John's solution. Just checkout that project into your plugins directory by executing 'bzr co lp:bzr-dumb-merge BzrDumbMerge' within the plugins directoy. This should hopefully work...

Greetz,
Jonny

Revision history for this message
Aaron Bentley (abentley) wrote :

Merge doesn't seem like the right tool in this situation. If you want to oversee text merges, then you would want to oversee file adds, deletes, and all other operations that a merge might perform.

The tla "update" command fit this role well, because it only applied the changes that were new since the last merge. bzr would need to record cherrypicks in order to emulate this.

Alternatively, you can simulate the update behavior with merge.

Let's say you have two branches, A and B, and each has a revision "2" that you don't want to merge.

$ bzr merge -d A B -r 3..5
$ bzr commit A -m "Merged from B"
# Make two commits to B
$ bzr merge -d A B -r 5..7
$ bzr commit A -m "Merged two revisions from B"
etc, etc.
# When merging back to B, use the most recent revision of A not merged into B
$ bzr merge -d B A -r 3..5

Martin Pool (mbp)
Changed in bzr:
status: Triaged → Confirmed
Jelmer Vernooij (jelmer)
tags: added: check-for-breezy
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.