Here is what I am trying to do. I have a commit to the default branch that I need off default. We build for production from default and this commit is not ready. So I have used hg backout to undo the changes from the default branch. Now I have created a new branch to store the changes. But when I attempt to transplant or graft the changes onto the branch I get told that I cannot graft in changes from an ancestor. This makes sense, but I need to pull changes from an ancestor, how do I do this.
I have tried
hg diff -c 8c13fc133926 > new_branch.diff
hg import new_branch.diff
but this Fails with no explanation. Any pointers?
EDIT
It seems I'm a little hard to follow, so I will try and clarify.
o Default with only ready changes
|
| o Not ready changes (new commit on a branch)
| |
|/
o Hg backout commit Undoing not ready changes from default
|
o Lots of other commits and merges to default
|
o ...
|
o Not ready changes (original commit)
The graph above shows where I need to get to.
I have done this by using hg diff -c 6877 | patch -p1 where 6877 is the revision of the commit that needs to be moved off of default.
But I think I am doing this wrong.
Make your new branch off of the revision BEFORE you made the "not ready changes" commit. I will call that revision 123:
hg up 123
hg branch NewBranch
hg ci -m "branching for NewBranch"
Now you can do your GRAFT, with no concerns about ancestors.
Tying up loose ends:
It seems that you'll already have another head on NewBranch, the one you said you created. You can merge with that or just close it. You can see the heads with:
hg heads NewBranch
I will call that unwanted head revision 456. And I would close it like this:
hg up 456
hg ci --close-branch -m "It was all just a dream... a terrible, terrible dream."
Which reminds me: you could have used the same technique (closing an unwanted branch head) instead of hg backout! Then you could have done the steps above ... except you'd be able to do a neat-and-tidy REBASE ("leaving no witnesses", like they say in the movies) instead of cherry-picking with GRAFT, and leaving behind the wreckage on the default branch!
I personally avoid grafting as much as possible, and your commit is already in the history. You seem to be using the correct commands, but it is hard to understand your issue, more information is needed.
How about creating your new branch from the commit that you wanted to backout?
o NewBranch: head, creation of the branch
|
|
o | default: head, Backed-out changeset
| |
|/
o default: commit (not ready)
|
|
o default: initial state
|
Another idea, if you don't care about grafting, simply start your new branch from the initial state, and transplant the commit; it won't be considered an ancestor anymore.
o NewBranch: head, grafted commit
|
/|
| o NewBranch: creation
| |
| |
o | | default: Backed-out changeset
| | |
|/ |
o / default: commit (not ready)
| /
|/
o default: initial state
|
Related
Given a branch called 'main'. As a developer wanting to work on a new feature, I create 'f1' and do several commits, pushing regularly to our central repo. While working on the feature, I need to get the changes form 'main' in my branch.
I know I can hg merge main to get the changes in 'f1'. But when I later integrate in 'main' then the history will be full of references to that temporary branch. Are there ways to make my branch work less visible after the fact?
To make branch less visible in history you should use bookmarks. Let's see both cases, with a named branch or with a bookmark.
With new branch named 'f1' from 'main':
$ hg update main
$ hg branch f1
...
$ hg glog --template "{rev} {branch} {bookmarks} {desc}\n"
# 5 main Hacking main.
|
| o 4 f1 Hacking f1.
| |
| o 3 f1 Hacking f1.
|/
o 2 main Hacking main.
|
o 1 main Hacking main.
|
o 0 default
With new bookmark named 'f1' from 'main':
$ hg update main
$ hg bookmark f1
...
$ hg glog --template "{rev} {branch} {bookmarks} {desc}\n"
# 5 main Hacking main.
|
| o 4 main f1 Hacking f1.
| |
| o 3 main Hacking f1.
|/
o 2 main Hacking main.
|
o 1 main Hacking main.
|
o 0 default
In the bookmark case the 'f1' feature can be removed from history with hg bookmarks --delete f1 (from Mercurial 2.3 new bookmarks are pulled by default WhatsNew) and there are two paths in the 'main' branch.
First of all, why do you worry about that the main branch would contain the history of the f1 branch after merging the latter to the former, if the f1 branch is already in the central repo??? The f1 branch is not temporary/disposable/invisible any more once it's pushed into the central repo, it's very visible to everyone who can access the central repo.
The answer to your question is: No way unless f1 is a by-cloning branch. All suggestions of using bookmark and/or anonymous branch are false.
I have two Mercurial repos C1 and C2 which both derived from the same parent P some time ago but have since had separate lines of development. In addition, in C2, there is a named branch B2 which happened since the diversion. I want to pull only branch B2 into C1, which I can easily do with hg pull C2 --branch B2.
Now B2 branches off of some points in the default branch of the C2 repo. So those default changesets from C2 get pulled over into C1 even though I am only trying to pull branch B2. (I can understand that since they are ancestors of the B2 changesets).
After the above pull, I will have two heads on the default branch of C1, the original head and the head composed of those default changesets that got pulled over as a result of pulling B2 over. I want to leave the default branch of C1 unchanged, otherwise I have two heads, keep getting told that updates "cross branches" and telling me I have to merge. (I will be pulling new default branch things into C1 from other external repos going forward).
How can I do the above so that I do not have two heads on default?
Thinking about the problem, am I right in thinking you have something like this?
# 4[tip]:1 439255c536ee 2013-01-25 10:42 +0000 rob
| More changes on original default branch
|
| o 3 379f384c1d73 2013-01-25 10:41 +0000 rob
| | Changes on named branch B2
| /
| o 2:0 d225da266931 2013-01-25 10:40 +0000 rob
| | Changes on cloned default
| |
o | 1 7088660d3ba6 2013-01-25 10:41 +0000 rob
|/ Changes on original default branch
|
o 0 a02a921256b3 2013-01-25 10:39 +0000 rob
Project Start
The problem you're describing is that while you want to keep the B2 branch, you don't want the two heads on default:
$ hg heads default --style=compact
4[tip]:1 439255c536ee 2013-01-25 10:42 +0000 rob
More changes on original default branch
2:0 d225da266931 2013-01-25 10:40 +0000 rob
Changes on cloned default
I can see two possibilities to "fix" this. One is simply to close the "cloned" default branch (at least in your repo):
$ hg update 2
$ hg commit -m "Closing cloned default" --close-branch
$ hg heads default --style=compact
4[tip]:1 439255c536ee 2013-01-25 10:42 +0000 rob
More changes on original default branch
This would mean that if you issue an hg update default, it shouldn't be ambiguous, which I guess is part of the problem.
An alternative would be to do a "null merge" from the other default branch:
$ hg update
$ hg -y merge --tool=internal:fail 2
$ hg revert --all --rev .
$ hg resolve -a -m
$ hg commit -m "Merged cloned default"
The main difference in these approaches is that using the --close-branch option, you can still see the extra head when you use hg heads -c... it is still a head, but it simply has a flag set in the metadata to say it's closed. You can still update to the closed branch, and even commit changes to it. Doing a merge you won't see the head at all, as it will not longer be a head.
Both of these methods mean that you can still pull changes to the B2 branch - however, if in the repo you're pulling from they make changes on default and merge those into B2 (often used when bugfixing, etc), you will hit the same problem later on, and have to repeat the above.
I hope that makes sense. Of course, if you later push to another repo, you will push the closed/merged changesets too. It would be wise to clone your repo and try these approaches locally to check if that's what you actually want.
I have a branch that was developed for a long period of time. During the development default branch was merged into that branch several times. I would like now to review all the changes done on that branch ignoring merges, to decide whether it is safe to merge it to default.
I tried
hg diff -r "branch('myBranch') - merge()"
but it still shows changes introduced by merges. Also tried following this How to show the diff specific to a named branch in mercurial but
hg diff -r "branch('myBranch') - branch('default')"
still bring changes introduced by merges.
You have to read about revsets syntax
Your case
hg log -r "branch('myBranch') and ! merge()"
The problem with your commands is that when you perform a hg diff and pass it several changesets, you actually perform a diff between those changesets, hence you will see the merge result.
If you want to see just the changes made by the changesets then you could use export:
$ hg export -r "branch('mybranch') and not merge()"
// lists the changes made by each changeset
For easier reviewing, you can output these to files with names based on the revision/changeset id:
$ hg export -r "branch('mybranch') and not merge()" -o "%H.patch"
... creates a file for each non-merge changeset in mybranch, and outputs it to a file with the name "40-digit changeset id.patch". If you'd prefer the revision number (only useful for your local repository as revision id's are local), use "%R.patch".
The following uses the log command but with the --patch parameter it can show the modified lines as well:
hg log --branch my-branch --no-merges --patch
Short form:
hg log -Mpb my-branch
That is a very good question, which I am trying to find good answer for a long time, and yet not found a good one. OK, one thing which 100% works is this:
hg status # make sure that you don't have local changes
hg up <target_branch>
hg merge <your branch>
hg diff > merge.diff
hg up -C # this one cleans the merge
I use this workflow all the time, but it does not satisfy me fully because it requires to switch branches (when I actually might not want to do actual merge right at this exact moment, I am just checking whats there)
I've been searching for ages for a good solution here, but so far there are none found. Tried those:
hg diff -r "branch('.') and ! merge()" # this page
hg diff -r "default:branch('.') and not merge()"
hg diff -r "parents(branch(.)):branch('.') and not merge()"
This problem also discussed in:
Mercurial: how can I see only the changes introduced by a merge?
which has good answer as: "so if you can define it unambiguously you might convince one of us Mercurial contributors that read SO to implement it."
Try:
hg diff -r"ancestor(default,my_branch)" -rmy_branch
If you haven't done any merges to the branch, then "ancestor" will pick up the original branch point. If you've done merges, then "ancestor" will pick up the latest merge point.
For example, on the graph below you'll get the diff between 520 and 519:
# 521 (default)
|
| o 520 (my_branch)
|/|
o | 519
| |
o | 518
| |
o | 517
| |
| o 516
| |
| o 515
| |
| o 514
|/
o 513
On the simpler graph below you'll get a diff between 516 and 513:
# 517 (default)
|
| o 516 (my_branch)
| |
| o 515
| |
| o 514
|/
o 513
Per Matt Mackall what you probably want is:
hg diff -r mainbranchrev -r mywork
He writes:
You may be under the impression that "a changeset is a delta" or
similar, and that this means that Mercurial can magically chain together
a bunch of non-contiguous deltas to construct a bigger delta that's just
your changes.
In fact, Mercurial is much simpler than that. A changeset is actually a
snapshot: a complete set of complete files representing the state of the
project at the time of commit. And a diff is simply the difference
between these two snapshots. So when you do:
hg stat --rev '3408::3575 and user(mdiamond) and not merge()'
..status simply uses the first and last changesets of the resulting set
to do its calculation.
When you do incremental merges on your development branch, you're
inextricably tangling your work with mainline development, and Mercurial
is not nearly smart enough to untangle it in the way you're asking. Your
best bet is to compare the head of your work with the head of the main
branch:
hg diff -r mainbranchrev -r mywork
..which will show all your work plus whatever merge fixups you had to
do.
Using Mercurial. Working in private clones, making changes, pushing to master. Etc. That's fine.
(By the way, let me state that I am familiar with many version control systems ranging from the classics SCCS, RCS, CVS, SVN to DVCSs like BitKeeper, Git, Mercurial, passingly familiar with Monotone, Darcs, Bzr. Not so familiar with Perforce, ... I just mention this for people who may be able to explain equivalents and similarities between systems.)
Unfortunately, other members of the project think that I check in too often. I use the "check in early and often" approach, sometimes checking in more often than once every half hour. They don't want to see so many checkin messages in the log.
NOT QUESTION: Now, I have taken to the habit of making most of my changes on branches (although hg lacks retroactive branching), summarizing all of the changes when I merge my task branches back to the trunk. hg log -b default allows them to filter out my task branches, and works okay when the merge messages are meaningful. This is not my question.
NOT QUESTION: similarly, I know how to use history editing, etc., to remove my fine granularity changesets, so that the only changesets that get pushed are coarse grain. (Although, by the way, I often find the simplest thing to do is move .hg directories around.) History editing ias annoying, but I can do it.
MY QUESTION: my question is: I would like to keep track of my fine granularity changesets and log messages, even though I don't push them to the project master repository.
Q: how do I do this?
I.e. how do I keep two repositories tracking each other, but NOT push all of my changes to the master? Preferably tag changesrts not to be pushed. (By the way, I prefer to say "tag a revision set". Changeset sounds too much like patch.)
The way I do it now is to have
a) the project master repo
b) my personal master repo, with all of the fine grain changes
c) one or more workspaces
Where
a) clone the project master repo to get the workspace (using hg clone, yyeah, I know)
b) work in the workspace clone with fine grain checkins (I know this)
c) push from the workspace clone to my personal master
d) and, when it comes time to push to the master, edit the history, and push that.
Two troubles:
1) conflicts merging or pushing from the workspace clone to my personal master
- more precisely, conflicts when merging from the master repo with history edited to remove the fine grain checkins, to my personal master with the fine grain checkins preserved.
2) I would like to record what has been pushed to the project master in my personal master.
--
A very simple example.
A task branch, with fine grain checkins.
o changeset: 1022:
| branch: default
| parent: 1017
| parent: 1021
| summary: Merged task branch onto main, default, branch, with changes to FOO and BAR
|
o changeset: 1021
|\ branch: task-branch
| | parent: 1020
| | summary: Merged default branch to task-branch, with changes to FOO and BAR
| |
| o changeset: 1020
| | branch: task-branch
| | parent: 1018:
| | summary: yet another fine grain checkin on a branch changing BAR for a second time
| |
o | changeset: 1019
| | branch: task-branch
| | parent: 1018:
| | summary: yet another fine grain checkin on a branch changing FOO
| |
o | changeset: 1018
| | branch: task-branch
| | parent: 1017
| | summary: yet another fine grain checkin on a branch changing BAR a first time
| |
|/
o changeset: 1017
| branch: default
| summary: some other changeset on the default branch, i.e. trunk
|
The edited history, that gets pushed to the project master
o changeset: 1018: ...changed checksumm because checksum seems to include history
| branch: default
| parent: 1017
| summary: Merged task-branch onto main, default, branch, with changes to FOO and BAR.
| Removed task-branch-history from what got pushed to project repo,
| although may still be in personal repo
|
o changeset: 1017
| branch: default
| summary: some other changeset on the default branch, i.e. trunk
|
The problem is, when I try to merge an updated projecvt master, that may look like
o changeset: 1019
| branch: default
| parent: 1018
| summary: again, some other changeset on the default branch, i.e. trunk
|
o changeset: 1018: ...changed checksumm because checksum seems to include history
| branch: default
| parent: 1017
| summary: Merged task-branch onto main, default, branch, with changes to FOO and BAR.
| Removed task-branch-history from what got pushed to project repo, ]
| although may still be in personal repo
|
o changeset: 1017
| branch: default
| summary: some other changeset on the default branch, i.e. trunk
|
I get conflicts, even though changeset 1018 of the project master and 1022 in the personal master are exactly the same, in terms of file contents.
I've tried not changing the comments in the merge changesrt that gets pushed. Doesn't help, at least not reliably.
I wonder if the full history is included in the changesets.
I also wonder if there is some merge tool that can recognize same files, even though different history and log messages.
In general any workflow that involves editing history is not going to work well. It's just not the intended work mode, and no effort goes into making it work well.
Better options for you might be:
Versioned Mercurial Queues (hg qinit --create-repo) which lets you make multiple commits iterating on a single patch. You get the full history in your private patch repo and they only get the qfinished whole.
Rather than merge back your task branch and edit history, just re-apply the change as a single commit and push that. In your example it would be hg diff -r 1017 -r 1021 | hg import, which creates a new commit (1022) that is the sum of all the changes 1018::1021, inclusive. that should merge cleanly and be pushable without ever having to push any changesets on your task-branch out to them. You can even hg commit --close-branch on the task branch
Tell your coworkers to STFU. ;) High changeset granularity is good practice, and they should adapt.
Also, consider using bookmarks instead of named branches for your task-branches. Similarly the new phases feature makes it possible to mark changesets in your task branches (be they bookmark-branches or old-style named-branches) as secret so they can't be accidentally pushed.
I've been doing some development on a branch and realized that before it could be complete something else need to be done first. I decided that I would branch my current branch and do the requiste changes in that branch then merge them back together and then merge my working branch into default. Basically I expected this:
| | + requiste work branch commit.
| |/
| + working branch commit
|/
+Default branch commit
and in the end what I expect to do is this:
+ Merge into defualt
|\
| + Merge requisite work into working branch
| | \
| | + requiste work branch commit.
| |/
| + working branch commit
|/
+Default branch commit
What I'm getting in both hg view and hg serve is this:
| + requiste work branch commit.
| |
| + working branch commit
|/
+Default branch commit
However, when I look at the commit log "requiste work branch commit" is marked as a part of a different branch.
Am I doing something wrong? Is this a bug in hg view and hg serve? Anyone experienced this before?
If there are no further commits on the first branch after "working branch commit" (except on the second branch), then the view may appear as a straight line (which is what you are seeing). I suspect that the reason for this is merely an optimization in the display code. As soon as you make another commit to the first branch, it should display the way that you are expecting.
The missing link here is that there is no commit on which is a child of "working branch commit" and not on the same branch as "requisite work branch commit". Thus, as one is a child of the other and there's nothing to show in a third column, you only see two columns. For the same reason, merging "req..." with "working..." is currently meaningless.