Bug 6372 - Push complains that it includes orphan changeset even if this changeset is already on the server.
Summary: Push complains that it includes orphan changeset even if this changeset is al...
Status: RESOLVED ARCHIVED
Alias: None
Product: Mercurial
Classification: Unclassified
Component: evolution (show other bugs)
Version: default branch
Hardware: PC Linux
: wish bug
Assignee: Bugzilla
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-07-15 07:05 UTC by Manuel Jacob
Modified: 2021-09-18 00:01 UTC (History)
2 users (show)

See Also:
Python Version: ---


Attachments
Code to demonstrate how various `outgoing` members don't do what is documented. (2.96 KB, patch)
2020-07-15 07:24 UTC, Manuel Jacob
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Manuel Jacob 2020-07-15 07:05 UTC
On push, Mercurial ensures that no obsolete and unstable changesets are included. However, when the obsolete or unstable changeset is already on the server, Mercurial still complains, unless the set of outgoing changesets is empty.

  $ cat >> $HGRCPATH <<EOF
  > [phases]
  > publish = False
  > [experimental]
  > evolution = true
  > EOF

  $ hg init server
  $ hg clone server client -q
  $ cd client

  $ echo root > root; hg add root; hg ci -m root
  $ hg branch foo -q
  $ echo A > A; hg add A; hg ci -m A0
  $ echo B > B; hg add B; hg ci -m B0

  $ hg push
  pushing to $TESTTMP/server
  searching for changes
  adding changesets
  adding manifests
  adding file changes
  added 3 changesets with 3 changes to 3 files

  $ hg up 1 -q
  $ hg ci -m A1 --amend
  1 new orphan changesets

  $ hg log -G -T '{rev}:{node|short} "{desc}"'
  @  3:8af15adf44a9 "A1"
  |
  | *  2:15102ccfca43 "B0"
  | |
  | x  1:a741f487acb6 "A0"
  |/
  o  0:1e4be0697311 "root"
  

FIXME: Push aborts even though 15102ccfca43 (B0) is already on the server.

  $ hg push
  pushing to $TESTTMP/server
  searching for changes
  abort: push includes orphan changeset: 15102ccfca43!
  [255]

  $ hg push --force
  pushing to $TESTTMP/server
  searching for changes
  adding changesets
  adding manifests
  adding file changes
  added 1 changesets with 0 changes to 0 files (+1 heads)
  1 new obsolescence markers
  obsoleted 1 changesets
  1 new orphan changesets

If there are no outgoing changes, it works.

  $ hg push
  pushing to $TESTTMP/server
  searching for changes
  no changes found
  [1]

Create unrelated changeset C0.

  $ hg up 0 -q
  $ echo C > C; hg add C; hg ci -m C0
  $ hg log -G -T '{rev}:{node|short} "{desc}"'
  @  4:a26de091fce5 "C0"
  |
  | o  3:8af15adf44a9 "A1"
  |/
  | *  2:15102ccfca43 "B0"
  | |
  | x  1:a741f487acb6 "A0"
  |/
  o  0:1e4be0697311 "root"
  

FIXME: Push aborts even though 15102ccfca43 (B0) is already on the server.

  $ hg push
  pushing to $TESTTMP/server
  searching for changes
  abort: push includes orphan changeset: 15102ccfca43!
  [255]

Explicitly pushing C0 works, even though 

  $ hg out -G -T '{rev}:{node|short} "{desc}"'

  $ hg push -r 4
  pushing to $TESTTMP/server
  searching for changes
  adding changesets
  adding manifests
  adding file changes
  added 1 changesets with 1 changes to 1 files (+1 heads)

As above, if there are no outgoing changes, it works.

  $ hg push
  pushing to $TESTTMP/server
  searching for changes
  no changes found
  [1]
Comment 1 Manuel Jacob 2020-07-15 07:24 UTC
Created attachment 2078 [details]
Code to demonstrate how various `outgoing` members don't do what is documented.
Comment 2 Manuel Jacob 2020-07-15 07:45 UTC
The code for checking outgoing changesets is in mercurial.exchange._pushcheckoutgoing(). The problem is the name and the usage of the `outgoing.missingheads` attribute. The name suggests that it contains the heads of the missing changesets, and that’s also what the docstring in the `outgoing` class says. However, `outgoing.missingheads` may contain changesets that are already on the server (causing this bug) or non-heads. What it actually contains is which revisions were passed to the push via `-r`, or `repo.heads()` by default, minus secret changesets. Therefore, `outgoing.missingheads` is not helpful for what we want to do here. (The attached patch shows how the `outgoing` members don’t conform to the documentation. A separate patch will be sent for fixing the name and documentation of `outgoing.missingheads`.)

The `outgoing.missing` attribute doesn’t have this problem. As the buggy logic is shortcut if `outgoing.missing` is empty, the bug doesn’t happen if there are no outgoing changes.

I see two ways to fix the actual problem:

1) Use `outgoing.missing`. This would have the advantage that all included obsolete and unstable changesets are shown.
2) Compute the heads of `outgoing.missing` and use them instead of `outgoing.missingheads`, and leave the code otherwise unchanged. This would mean that, like now, only the first encountered obsolete or unstable changeset is shown.
Comment 3 Pierre-Yves David 2020-07-16 04:52 UTC
Solution 2) seems like a good fit.
Comment 4 Manuel Jacob 2020-07-17 02:28 UTC
I ended up implementing solution (1), as I think it’s more helpful for the user.
Comment 5 HG Bot 2020-07-20 12:30 UTC
Fixed by https://mercurial-scm.org/repo/hg/rev/5631b0116374
Manuel Jacob <me@manueljacob.de>
discovery: fix docstring of `outgoing` class

Also, introduce a more correct name `ancestorsof` for what was named
`missingheads` before. For now, we just forward `ancestorsof` to `missingheads`
until all users are changed.

There were some mistakes in the old docstring / name:

* `missingheads` (new name: `ancestorsof`) contains the revs whose ancestors
  are included in the outgoing operation. It may contain non-head revs and revs
  which are already on the remote, so the name "missingheads" is wrong in two
  ways.
* `missing` contains only ancestors of `missingheads`, so not *all nodes*
  present in local but not in remote.
* `common` might not contain all common revs, e.g. not some that are not an
  ancestor of `missingheads`.

It seems like the misleading name have fostered an actual bug (issue6372),
where `outgoing.missingheads` was used assuming that it contains the heads of
the missing changesets.

(please test the fix)
Comment 6 Manuel Jacob 2020-07-20 18:37 UTC
The actual fix is in https://www.mercurial-scm.org/repo/hg-all/rev/c26335fa4225
Comment 7 HG Bot 2020-07-21 02:10 UTC
Fixed by https://mercurial-scm.org/repo/hg/rev/a381618210d0
Manuel Jacob <me@manueljacob.de>
tests: test that push doesn’t complain about unstable changesets if no changes

When there’re no outgoing changes, push doesn’t complain about unstable
changesets.

There is currently a bug (see issue6372) that causes that there is an abort on
push when the outgoing changes contain another changeset even if that is not
obsolete or unstable. A test case and fix for that is sent in the next patch.

(please test the fix)
Comment 8 Bugzilla 2020-07-29 00:01 UTC
Bug was set to TESTING for 7 days, resolving
Comment 9 Manuel Jacob 2020-07-29 00:07 UTC
The fix was backed out in 6063c1857d0a.
Comment 10 Bugzilla 2020-12-26 00:00 UTC
Bug was inactive for 150 days, archiving
Comment 11 Manuel Jacob 2021-04-16 08:32 UTC
Here’s another test case. It shows a case which the current check misses and a case which the current check rejects for no good reason.

  $ . $TESTDIR/testlib/push-checkheads-util.sh

  $ mkdir test
  $ cd test
  $ setuprepos
  creating basic server and client repo
  updating to branch default
  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
  $ cd client
  $ mkcommit B0
  $ hg log -G --hidden
  @  d73caddc5533 (draft): B0
  |
  o  8aaa48160adc (draft): A0
  |
  o  1e4be0697311 (public): root
  
  $ hg push
  pushing to $TESTTMP/test/server
  searching for changes
  adding changesets
  adding manifests
  adding file changes
  added 1 changesets with 1 changes to 1 files

Obsolete A0, making B0 orphan.

  $ hg debugobsolete `getid "desc(A0)" `
  1 new obsolescence markers
  obsoleted 1 changesets
  1 new orphan changesets
  $ hg log -G --hidden
  @  d73caddc5533 (draft): B0
  |
  x  8aaa48160adc (draft): A0
  |
  o  1e4be0697311 (public): root
  

Pushing makes B0 orphan on the server, but it’s not prevented.

  $ hg push
  pushing to $TESTTMP/test/server
  searching for changes
  no changes found
  1 new obsolescence markers
  obsoleted 1 changesets
  1 new orphan changesets
  [1]

Add an unrelated changeset.

  $ hg up 0 -q
  $ hg branch unrelated -q
  $ mkcommit C0
  $ hg log -G --hidden
  @  d4abdb58a1dc (draft): C0
  |
  | *  d73caddc5533 (draft): B0
  | |
  | x  8aaa48160adc (draft): A0
  |/
  o  1e4be0697311 (public): root
  

Pushing fails for no good reason (B0 is already orphan on the server).

  $ hg push --new-branch
  pushing to $TESTTMP/test/server
  searching for changes
  abort: push includes orphan changeset: d73caddc5533!
  [255]
Comment 12 Bugzilla 2021-09-18 00:01 UTC
Bug was inactive for 154 days, archiving