Mercurial: How to ignore multiple heads of a branch when used as ancestor on a closed branch - version-control

Another git user confused by Mercurial branches here. I've done something that I can't figure out how to undo and as a result I cannot push my totally unrelated changes. Any help would be appreciated.
Here's the story, I think:
I started working on something on default. I realized this was a mistake as it would become a PR, so the next commit I did on a branch feature1. I then submitted a PR on bitbucket.
I started working on something else, also off of default, this time I was certain to use a branch feature2, and I did purposely "hg up -r ..." with the revision number before my feature1 commit so as not to include that change.
At this point the history looks something like,
-- G (default) - H (feature1)
/
.. D - F (default)
\
-- I - J - K (feature2)
My PR was not accepted, so I close feature1.
There has been development on default in the parent repository, so I hg pull. Now it looks something like,
-- G (default) - H (feature1) [my repository, closed]
/
.. D - F (default)--- L (default) [parent repository]
\
-- I - J - K (feature2) [my repository]
.. plus lots of changes on other branches that I don't know anything about.
But I'm happy with feature2 and I want to make a PR for it, so I try to hg push --new-branch, but I get the message,
abort: push creates new remote head 7a341084eb8a!
Ok, so use hg glog and it appears the checksum corresponds with the parent work, i.e. L in the diagram above. Mercurial seems to be complaining that I have a commit on a closed branch with the branch default that has not been merged into default! But I don't want it to exist anymore! However, I don't want to strip it as then it would make reading the old, closed PR impossible.
If I try to push just my own branch, hg push --new-branch -b feature2, then I get:
abort: push creates new remote head 062efd5d0886!
i.e., same problem but with a different head. This one appears to correspond with the first patch of feature2! That is, I in my diagram.
This makes no sense.. a closed branch is stopping me from pushing the changes on an entirely other branch. Meanwhile I can't figure out what multiple heads it's even talking about when pushing my feature2 branch, since there is really only one feature2. The recommendation is to "merge" before pushing, but I can't even figure out here what to merge. I don't want to merge my rejected change on default, and when I do hg merge default on feature2, thinking maybe I need to take into account the latest upstream changes, this merges G, from my closed branch instead of the upstream head.
So, clearly, I just don't understand Mercurial branches. In git I would just delete the feature1 branch and that would be that. How do I resolve this?

But I'm happy with feature2 and I want to make a PR for it, so I try to hg push --new-branch, but I get the message,
abort: push creates new remote head 7a341084eb8a!
At this point, revision L is the head of branch default, and you are trying to send revision G. Revision G is in the default branch, so you will create another head. The branch feature1 was closed, but not the default branch in the revision G. You can update to revision G, and close the branch there, or merge it with revision L.
If I try to push just my own branch, hg push --new-branch -b feature2,
then I get:
abort: push creates new remote head 062efd5d0886!
If revision I is in the default branch, you have the same problem as above.
If not, try hg push -r <rev number of revision I>.

Related

Eclipse Git - switch branch without merge

This is maybe a dumb question, but I could not find a way to solve my problem. I am working with Eclipse and Git.
When switching and pulling branches to work on different features, the local commits of the previous branch are added to the commit history of the new branch.
Let say I am working on a branch A, commit twice, then I create from master a branch B, switch to this branch B, pull, and perform one commit. Now my branch B contains the changes made on branch A + the commit made on branch B, making it difficult to create a pull request to merge the change of the only commit B to master.
I would like my local commits/changes to be erased when switching to another branch. How can I do that with Eclipse Git?
After playing around with eclipse, I noticed there was two possible pull actions:
The default one does Fetch + merge, resulting in the mess described in the question
The other option allow you to select Fetch + rebase, to rebase your working directory to the state of the remote branch.
Based on this answer https://stackoverflow.com/a/17324792/10631518 you can even make rebase the default behaviour by running
git config branch.autosetuprebase always

git multiple pull requests

I'm a git noob in a shared environment, but have used it for personal projects fine.
I'm trying to contribute to a project, so I did this:
Forked the project.
Made code changes.
Committed code changes to my local branch.
Pushed changes to my fork
Did a pull request.
That worked great. PR is still pending, but I had some other ideas.
So, I created a new local branch.
Made code changes
Committed code changes to local branch
Pushed changes to my forked copy
Did a PR
The code changes from my previous edits are obviously in place with this PR. I do not want that, since they haven't been committed to the main branch.
Likewise, I want to make additional changes and push them specifically without containing the code from my previous work.
How is this accomplished?
Since you already started a second pull request, you'll have to forego best practices:
rebase your local <PR-2-branch> to start of PR-1 (say 8 commits ago). use -i to start an interactive session.
git rebase -i HEAD~8
In the editor window that opens up, hit i and mark commits from PR-1 (5 commits) to be drop or d and pick or p commits from PR-2 (3 commits)
d 113456 <message>
d 223456 <message>
d 333456 <message>
d 443456 <message>
d 553456 <message>
p 663456 <message>
p 773456 <message>
p 883456 <message>
Press Esc > w > q to exit the editor and to proceed with the rebase.
The branch now contains only commits within the scope of current PR.
Update the remote branch with --force
git push origin <PR-2-branch> --force

Egit pull and merge changes

I was working locally on master branch. (by mistake) but it's ok with me this time as I control my code.
I took the following steps:
Egit->commit and push (to master)
Egit -> pull (to get other developers changes)
I got a message that there is a conflict with one file and I merged it.
Now I see: [My Product | Merged Master (up arrow)2 (down arrow)1]
I see in the symbols next to the files that the other developers created - black sign as if there are uncommitted.
A. What does the 2 up arrow and 1 down arrow mean?
B. Why do I see uncommitted changes? they are not mine
C. How can I work out on master after my merge?
D. I looked in bitbucket and didn't see that my changes were committed to the remote branch. What is wrong?
I know that I am supposed to work on branches - but for now - how do I fix the situation?
A. Two arrows up means you have two commits in your local branch that aren't in the remove branch. The one arrow down means there is one commit in the remote branch that you don't have locally. The solution is to do a git pull followed by a git push
B. Uncommitted changes are probably from your conflict. After a conflict, you have to resolve the conflict, add it to index and then commit that change. This is known as a merge commit. My guess is you have not done this.
C. Work out on master? You mean you want to work directly on top of master? After you resolve your conflict, you should be all set to do that. Branching is better though. To create your own branch just do git checkout -b my_featue_branch

Mercurial merge creates new head in subrepos

I am working on a large project, with a main repository and multiple subrepos, organized like this:
main-repo
sub-a
sub-b
sub-c
Each person working has one or more named branches of their own. I am working in a branch that we will call shastings-dev and a co-worker has a branch that we will call coworker-dev. (Both of these branches exist in main-repo, sub-a, and sub-b; neither exists in sub-c and we are both using someone else's branch for that one.)
My problem is that I can no longer merge changes from coworker-dev without creating a new head somehow. This sequence of commands has the unexpected effect:
hg pull
hg branch # prints: shastings-dev
hg merge --tool internal:other coworker-dev
hg commit -m "merge coworker-dev" --subrepos
hg push
The hg push prints this message:
abort: push creates new remote head 945a60694252 on branch 'shastings-dev'! (in subrepo sub-a)
EDIT -- I am breaking the question here and putting the answer. The rest of the question will be left intact below for anyone who is really interested in all the details.
The solution: for each subrepo that needed a merge, change directory to the subrepo and follow these steps:
hg update --clean shastings-dev
hg merge --tool internal:other coworker-dev
hg commit -m "merge coworker-dev"
hg push
(I did this for subrepos sub-a and sub-b. For sub-c I just ran hg update correct_branch_name to make sure that it was at the head as well.)
Then, once each subrepo has been properly updated, return to the containing repo, and:
hg commit -m "commit .hgsubstate after merging in subrepos"
hg push
As a result of this experience, I am going to adopt a new rule:
If you have problems with subrepos, always retry the commands in the individual subrepos.
What confused me was that hg update --clean switched all the subrepos, but didn't actually update them. The heads for the subrepos belonged to a different branch than the one showing with hg branch. As a result, #zerkms's comment was correct: the subrepos actually were not on the head and the merge really was creating a new head.
In other words, even if hg id shows that the main repo is at the head, that doesn't mean the subrepos updated properly and are also at their respective heads. Check the subrepos individually to figure out the real state of things.
EDIT -- rest of original question is below.
My first thought was that my local copy of the repo was somehow scrambled. So I cloned an absolutely fresh copy of the repo, verified that hg pull didn't bring anything new in and tried the merge/commit/push again. Same problem.
I have tried doing the merge/commit/push in the subrepo then doing commit in the main repo (to update .hgsubstate) and then doing merge/commit/push in the main repo. No joy.
I have tried using TortoiseHg on Windows to clone the repo, update to branch shastings-dev, and then merge/commit/push. Same problem.
So now my questions:
Why is a new head being created? Am I doing something wrong, is there something wrong with my branch, or is this expected behavior?
What should I do? Can I eliminate this multiple heads problem, or should I push with -f and then close the older of the two heads with hg commit --close-branch?
What bad things might happen if I use hg push -f? My personal rule is "don't do that unless you are a Mercurial expert" and I'm not a Mercurial expert. (So my actual personal rule is "never use hg push -f.")
By the way, I am not working on any files that coworker is working on. At this time I have only minor differences from coworker-dev and I would be willing to totally lose all history on branch shastings-dev, as long as I can get a working up-to-date branch with the same name. (If I lose my changes I am willing to copy the changed files over again. I just want Mercurial to work as expected again.)
EDIT: I am on a branch head when I do the above.
$ hg heads
changeset: 1515:803ea844dc8a
branch: coworker2-dev
tag: tip
user: coworker2
date: Tue Oct 08 17:33:31 2013 -0700
files: .hgsubstate
description:
Fixed some stuff in the foo bar.
changeset: 1513:1e76e6a43d83
branch: coworker-dev
parent: 1509:5e5392aded0a
user: coworker#place_where_i_work.com
date: Tue Oct 08 16:44:04 2013 -0700
files: foo.java bar.java baz.java quux.java
description:
Added more support to the foo bar for release.
changeset: 1422:8705d62db8f2
branch: shastings-dev
user: shastings#place_where_i_work.com
date: Wed Oct 02 21:08:39 2013 -0700
files: .hgsubstate
description:
Finish adding files
...many others not copied here...
$ hg id
8705d62db8f2 (shastings-dev)
$ hg update --clean shastings-dev
resolving manifests
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg id
8705d62db8f2 (shastings-dev)
$ hg merge --tool internal:other coworker-dev
...much output not copied here...
$ hg commit -m "merge coworker-dev" --subrepos
...much output not copied here...
$ hg push
pushing to https://path/to/repo/dir/main-repo
pushing subrepo sub-a to https://path/to/repo/dir/sub-a
searching for changes
new remote heads on branch 'shastings-dev'
new remote head 85d8faada6c4
new remote head 90ce145db695
abort: push creates new remote head 85d8faada6c4 on branch 'shastings-dev'! (in subrepo sub-a)
(you should pull and merge or use push -f to force)
As I said, when I had problems, I re-cloned everything. So the status is clean: I have no modified files.
Also, I have one other branch, and I tried the above sequence with the other branch. It happened again just as described. So, if anything is wrong, I figure it must be wrong in branch coworker-dev and not in my own branches.
Why is a new head being created? Am I doing something wrong, is there something wrong with my branch, or is this expected behavior?
You're not on the branch head, so merge creates another one
-- A (you're here) --- B --- C (head #1)
\
D (merge, head #2)
So you need to make sure you're on the head using hg id and hg heads. And if no - hg up
What should I do? Can I eliminate this multiple heads problem, or should I push with -f and then close the older of the two heads with hg commit --close-branch?
You should solve the real issue. See the advice above
What bad things might happen if I use hg push -f? My personal rule is "don't do that unless you are a Mercurial expert" and I'm not a Mercurial expert. (So my actual personal rule is "never use hg push -f.")
My personal rule is - to never use -f. After 4 years of experience with mercurial I don't see any good reason to use it at all. What may happen - as soon as there are 2 heads, what would hg up branchname do? What would hg up do?

Is this a situation where I should "hg push -f"?

I have two machines, A and B that both access an external hg repository.
I did some development on A, wasn't ready to push changesets to the external, and needed to switch machines, so I pushed the changesets to B using hg serve. Changesets continued on B, were committed and then pushed to external repo.
I then pulled on A and updated to default/tip. This left the local changesets that had previously been pushed to B as a branch, but because of how I pushed things around, the changes in the local changesets are already in default/tip.
I've now continued to make changes and commit locally on A, but when I try to push hg asks me to merge or do push -f instead. I know push -f is almost never recommended.
This situation is close to one where I should use rebase, however the changesets that would be "rebased" I don't really need locally or in the external repository since they are already effectively in default/tip via the push to B.
Now, I know I could merge with the latest local changeset and just discard the changes, but then I would still have to commit the merge which gets me back into rebase territory.
Is this a case where I could do hg push -f?
Also, why would pushing from A create remote heads if I've updated to default/tip before I continued to commit changesets?
I would back up my A & B repositories and then try this:
rem Machine A
rem ---------
hg merge
hg commit -m"merge"
hg push
rem Machine B
rem ---------
hg pull
The merge should ensure that you have one instance of each changeset visible from the tip, plus an additional merge changeset with no file changes. It should be safe to push the committed merge - although I would check this before doing it.
One of the features of Mercurial is that it is good at merging, so you could try to take advantage of this. If you are nervous about the effect of a merge you could try:
hg merge --preview
to get a better idea of what it is about to do.
If you really want an unbranched history, then you could create a clean clone of the external repository [if it isn't too big] and apply your changes from A as patches.