Merging to an empty branch doesn't work

Bug #82555 reported by Henry Ludemann
172
This bug affects 22 people
Affects Status Importance Assigned to Milestone
Bazaar
Confirmed
High
Unassigned
Breezy
Triaged
Low
Unassigned

Bug Description

Merging to an empty tree doesn't work (merge corner case)

Attempting to merge to a branch without commits doesn't work correctly.
eg:
mkdir bob
cd bob
bzr init
cd ..
bzr branch bob branch
cd branch
touch some_file
bzr add some_file
bzr commit -m "some change on a branch"
cd ../bob
bzr merge ../branch # Fails here, due to merge requiring checkins
bzr status # even if merge worked, I would fail
bzr diff # and I wouldn't detect changes
bzr commit -m "I wont work either, due to not detecting changes"
bzr log # And even if the rest were fixed, I would give bad history

The reason it doesn't work is that the merged revision on the 'bob' branch will only have a single 'parent', a special case which is assumed by bzrlib.commit.Commit._check_pointless to mean it contains no new merges. This is a corner case I hit when converting a repository to bzr[1].

Allowing the commit to succeed is as simple as updating the logic in bzrlib.commit.Commit._check_pointless, from
  if len(self.parents) > 1:
to
  if len(self.parents) > 1 or (len(self.branch.revision_history()) == 0 and len(self.parents) > 0):
which will correctly check to see if we have any pending merges.

Unfortunately however, as parent_ids[0] and parent_ids[1:] are special cased throughout the code, other areas also break[2].

I believed the correct fix was to seperate the 'parent' and 'merged' revisions (in bzrlib.revision.Revision.parent_ids, and bzrlib.commit.Commit.parents), as they are treated differently in the code. Some parts of the code seem to suggest it was originally split up in this way (eg: bzrlib.workingtree.WorkingTree.pending_merges)...

I did this, but unfortunately it was still not enough; the topological sort routines in bzrlib.tsort take a raw parent list (and so are unable to differentiate between merges and parents at the first revision). This causes the log and annotate results to be distorted, causing the revisions we are merging in appear on the mainline. A complete fix would probably require the parent / merged id split distinction to be present all the way to the repository...

Attached are three bundles;
* The first is a blackbox test to confirm that we can perform the 'init/branch/commit/merge/commit/log'
* The second bundle works around the entire issue, by refusing the merge when we have no revisions (and suggests 'bzr pull'). (also sent to the mailing list)
* The third attempts to fix the parent special case by breaking the tree parent_ids into parent_id and merged_ids (which works correctly for bzr diff and bzr status, but bzr log etc are still broken due to the topological problems). This is just a demonstration (all unit tests still pass after it, except for the attached merge test, but there are lots of deprecated warnings as get_parents was marked deprecated).

[1]
This is a corner case I hit when converting a sub-directory of a repository to bzr; I've been working on updating tailor so that the cvs frontend detects branch origin and merge points, and that the bzr backend will use that information to fully convert a repository. This corner case was hit when converting a module that was a sub-directory of a branch, where this sub-directory was added on a branch (so from the perspective of this directory, we branched from an empty tree, added the initial version, then merged back to integration).

This can happen any time the initial revision is added on a branch, then merged back (an operation that admittedly doesn't make much sense in a distributed system like bzr, but makes perfect sense on a centralised system).

[2]
Some areas that special case the parent check are bzrlib.commit.Commit._check_pointless, bzrlib.workingtree.WorkingTree.basis_tree, bzrlib.workingtree.WorkingTree.annotate_iter, bzrlib.status.show_pending_merges, bzrlib.builtins.cmd_update.run, bzrlib.builtins.cmd_remerge.run...

Tags: merge
Revision history for this message
Henry Ludemann (misc-hl) wrote :

Added blackbox unit test

Revision history for this message
Henry Ludemann (misc-hl) wrote :

Add bundle to suggest 'pull' when attempting to merge to an empty branch

Revision history for this message
Henry Ludemann (misc-hl) wrote :

Add bundle that attempts to remove the disparity between parent revision and merged revisions. Still not enough though, as the topological sort routines work on a raw parent list.

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

I think this has been merged into core. I know we get an error when trying to merge into an empty branch, suggesting that we use pull.

Can someone confirm?

Changed in bzr:
assignee: nobody → misc-hl
importance: Undecided → Medium
status: Unconfirmed → Needs Info
Revision history for this message
Kent Gibson (warthog618) wrote :

None of Henry's patches are in bzr.dev 2481, so it hasn't been merged into the core.
bzr does give a warning when merging into an empty branch:

bzr: ERROR: This branch has no commits. (perhaps you would prefer 'bzr pull')

Performing a pull succeeds.
That would seem to be sufficient - use pull in this situation instead of merge.

Revision history for this message
Dan Watkins (oddbloke) wrote :

The following sequence of commands:
  mkdir bob
  cd bob
  bzr init
  cd ..
  bzr branch bob branch
  cd branch
  touch some_file
  bzr add some_file
  bzr commit -m "some change on a branch"
  cd ../bob
  bzr merge ../branch
produces a branch on which 'bzr log' shows nothing. However, if you then 'bzr commit', it claims to have committed revision 1 while 'bzr log' starts showing 2 revisions. This is Not Right(TM).

Changed in bzr:
assignee: misc-hl → nobody
status: Incomplete → Confirmed
Revision history for this message
Daniel Clemente (n142857) wrote :

Another way to reproduce it easily is shown at bug 242175. When tried, it raises the error:
bzr: ERROR: Reserved revision-id {null:}

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

The same root cause also affects the join command

Revision history for this message
Gareth White (gwhite-deactivatedaccount) wrote :
Download full text (5.3 KiB)

I ran into this today by accident. It's even more confusing with a 2a repository as "bzr status" incorrectly reports the merged file as renamed and tells you to update. If you then update you either get a conflict and an error (2.0.3), a crash (2.0.4) or a different error (2.1.0rc1). Revert may then crash too.

Since it sounds like this is pretty hard to fix can we not make it detect you're merging into an empty branch and just abort the merge altogether (with a friendly error message)?

Current behaviour with 2.0.3:
> bzr init branch1
Created a standalone tree (format: 2a)
> bzr init branch2
Created a standalone tree (format: 2a)
> cd branch1
> touch test
> bzr add test
adding test
> bzr commit -m "test"
Committing to: /Users/garethw/Programming/Bazaar/branch1/
added test
Committed revision 1.
> cd ../branch2
> bzr merge ../branch1
+N test
All changes applied successfully.
> bzr status
working tree is out of date, run 'bzr update'
renamed:
  test => test
> bzr update
-D test
Path conflict: test / test
1 conflicts encountered.
bzr: ERROR: Reserved revision-id {null:}
> bzr revert
bzr: ERROR: exceptions.ValueError: Cannot have multiple roots.

Traceback (most recent call last):
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/commands.py", line 842, in exception_to_return_code
    return the_callable(*args, **kwargs)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/commands.py", line 1037, in run_bzr
    ret = run(*run_argv)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/commands.py", line 654, in run_argv_aliases
    return self.run(**all_cmd_args)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/builtins.py", line 4053, in run
    self._revert_tree_to_revision(tree, revision, file_list, no_backup)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/builtins.py", line 4063, in _revert_tree_to_revision
    report_changes=True)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/mutabletree.py", line 53, in tree_write_locked
    return unbound(self, *args, **kwargs)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/workingtree.py", line 2067, in revert
    report_changes)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/transform.py", line 2510, in revert
    working_tree, target_tree, tt, filenames, backups, pp)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/transform.py", line 2537, in _prepare_revert_transform
    merge_modified, basis_tree)
  File "/Users/garethw/Programming/Bazaar/bzr-repo/2.0.3/bzrlib/trans...

Read more...

Revision history for this message
Matthew Fuller (fullermd) wrote :

In addition to above-mentioned bugs, see also bug 249074, bug 308562.

Revision history for this message
Martin Pool (mbp) wrote :

Is this a dupe of bug 56663?

Jelmer Vernooij (jelmer)
tags: added: merge
Revision history for this message
Martin Packman (gz) wrote :

Making this bug the master for merging empty branch problems, but see also bug 308562 comment 5 which has a nice summary of different bugs filed around this issue.

Jelmer Vernooij (jelmer)
Changed in bzr:
importance: Medium → High
Revision history for this message
Alex Lewis (alexlewis-deactivatedaccount) wrote :

In case it helps Bug 709118 is caused by this bug.

Revision history for this message
Martin Pool (mbp) wrote :

this is very similar to or a dupe of bug 242175 (now fixed)

Revision history for this message
Martin Packman (gz) wrote :

I think bug 242175 was targeted just at showing a better error than a traceback, whereas this one was about actually doing something useful.

Revision history for this message
riddle (riddlepl) wrote :

Any news? Its 5 years already...

Revision history for this message
Sam Kottler (skottler) wrote :

Just want to give this a quick bump - any movement around fixing this issue?

Jelmer Vernooij (jelmer)
Changed in brz:
importance: Undecided → Medium
Jelmer Vernooij (jelmer)
Changed in brz:
status: New → Triaged
importance: Medium → Low
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.