I've read the RebaseProject page and tried a non-trivial example
(not rebasing a complete branch). It's similar to the case rebase D on
I of the scenario B.
Here's the situation before the rebase:
default : 0 ----- 2
\
feature : 1 ----- 3
Now I'd like to rebase 3 on 2, giving:
default : 0 ----- 2 ----- 3
\
feature : 1
Unfortunately the exact commands aren't given in the RebaseProject
page, but from my understanding of the usage synopsis it should be:
hg rebase --source 3 --dest 2
But somehow my understanding must be flawed, because I get a rebase combined with a merge:
default : 0 ----- 2 ----- 3
\ /
feature : 1 -------
Why is that?
Commands to reproduce the scenario:
hg init
touch a
hg add a
hg commit -m "added a"
hg branch feature
touch b
hg add b
hg commit -m "added b on feature"
hg up -C default
touch c
hg add c
hg commit -m "added c on default"
hg up -C feature
echo "feature" >> a
hg commit -m "changed a on feature"
hg rebase --source 3 --dest 2
Your scenario looks very similar to part rebase G onto I of scenario B of the Rebase Project Scenarios:
Scenario B
...
...
rebase G onto I
In your scenario, D == 1, I == 2 and G == 3. After rebasing, 3 maintains its relationship to 1 just like G' maintained its relationship to D. This is because D is not an ancestor of I and:
Note: Rebase drops a parent relationship only if the parent is an ancestor of target.
You really want to remove that relationship, then, according to the docs, you need a development version to get the --detach option:
Using a development version is available the new --detach option that drops this relationship.
Related
Simple question:
Let's say I have local commits like following:
master -> a -> b -> c
I want to merge a and b. What is the hg command for this? I tried
hg up b
hg fold -r a
got an error saying: abort: cannot fold chain not ending with a head or with branching
I tried
hg up b
hg amend
This created a stack like
master -> a.preamend -> b -> c
\-> a
which doesn't allow me to continue on c. Finally, I tried
hg up b
hg histedit a
abort: can only histedit a changeset together with all its descendants
No luck. What I want is something like:
hg up b
hg *merge* -r a
returns
master -> b -> c
Thanks in advance!
About error message
This error message saying abort: cannot fold chain not ending with a head or with branching occurs when new unstable changes are not allowed in your repository.
Unstable changes are those obsolete changes whose children(s) are not obsolete. You should look for experimental.evolution in hg config and add "unstable" to it.
About folding changesets
There are two ways to fold commits in the middle of stack using fold.
Use --exact option : You can do hg fold -r a -r b --exact. In this it does not matter what is the parent of your working directory is. You have to mention the revisions to be folded.
Update to the last child which you want to prune, in this case it is b, using hg update -r b. Then run hg fold -r a. The revision passed to fold must be the initial revision of the chain which you want to fold.
You had
master -> a -> b -> c
You folded a and b, they became obsolete, since b has a child c which is not obsolete, it is an unstable changeset.
So what you are doing is not wrong, it's just not allowed according to your configuration.
if you want to squash the changes from two commits in to one commit then, you can use hg rebase command to squash the changes.
$ hg rebase -r a::b -d master --collapse
this will squash the changes of both a and b commits in to one commit
for more info refer to: RebaseExtension
My revision graph looks like:
F
|
E
|\
| |
C |
| D
| |
B |
| |
|/
|
A
I want to collapse all commits from B to F into a single one. A is not mine, and I don't want to touch it. I'd like to have in the end:
X
|
A
Is this possible ? I've tried various collapse and rebase commands but could not achieve this.
You can accomplish this with the mq extension for the patch queue. You will need to remove the merge changeset (since I don't think you can qimport a merge) and reorder the patches (which may require some hand merging of the patch file).
hg qimport --rev F --name F
hg qpop
hg strip -r tip -- this removes the merge changeset
hg qimport -r C -n C
hg qpop
hg qimport -r B -n B
hg qpop
hg qimport -r D -n D -- now you have all 4 changes (D, B, C, F) in the patch queue
At this point you can hg qpush --all to apply all the patches and you will need to resolve all the conflicts that result in rejected patches. This is to manually redo the work that the merge changeset E had previously accomplished. Once that is completed via editing and hg qref commands, qpop all the patches except for D.
hg qfold B C F -- this will merge the B, C, and F patches into patch D
hg qfin D -- this will convert patch D into a finalized changeset
A few more notes:
As always, back up your work before you start (a copy of the folder is fine). You can also use your diff tools after the steps to compare the original and the result to ensure that you didn't miss anything.
If you have pushed any of those changesets to another repo, you will need to delete them there (either with hg strip or changing their phase to secret).
If the merge changeset E did a lot of work (i.e. there were conflicts between B+C and D) the extra step between 9. and 10. will be messy since your typical merge tools are not available.
The follow up question I have for you though: Why? What do you hope to accomplish? Branching and merging with smaller changesets is standard operating procedure with DVCS. After a few more changes, all those changes will scroll into history and never come up again. Worrying about a perfect history graph is really unnecessary.
I have 2 branches in my Mercurial repository. 'default' and 'other'
default branch A - B - C - D
other branch E - F
I need to move B changeset to other branch.
So it will look like this:
default branch A - C - D
other branch E - F - B
Is it possible?
Thanks in advance!
Graft-based solution
Graft (hg help graft) B to target branch
Remove (histed extension) B from source branch (graft only make copy of changeset, without removing original)
Rebase-based solution
Rebase B to other branch
Because rebase move also descendants of rebased changeset - rebase C back to default
The following solution doesn't require enabling any extensions. It does assume the existence of the patch utility, though.
On default:
$ hg diff -c B > diff.out
$ hg backout --merge -r B
$ hg merge
$ hg ci
On other branch:
$ patch -p1 < diff.out
$ hg ci
Is there a way to clone a part of a mercurial repo (i.e. clone -r xxx), but keep all changesets prior to the specified revision i.e. not just the ancestors?
For example, given a repo that looks like this:
-- 2 (branch default) -- 5 -- 8 (merge) -- 9 (merge) --
/ / /
0 -- 1 -- 3 (branch foo) ------ 6 -- /
\ /
-- 4 (branch bar) ------ 7 -------------
I would like to clone only the commits prior to the merge, i.e. so the resulting repo looks something like this:
-- 2 (branch default) -- 5
/
0 -- 1 -- 3 (branch foo) ------ 6
\
-- 4 (branch bar) ------ 7
but running
hg clone -r 7 repo repo2
will only give me commits 1, 4, and 7 (branch bar). It appears the only way to get what I'm after is something like this:
hg clone -r 5 repo repo2
cd repo2
hg pull -r 6
hg pull -r 7
Is that correct, or does someone know of a quicker way to do this?
You have to read hg help clone and remember options, which can be used more than once in one clone (-r and -b namely).
You want, in plain words "clone all in default to 5 inclusive and FOO branch and BAR branch"
Translate it into clone
hg clone -r 5 -b foo -b bar <SRC REPO> <DST-REPO>
hg help clone says
-r --rev REV [+] include the specified changeset
This is different than hg help log, for example, which says
-r --rev REV [+] show the specified revision or range
The best you'll be able to do is use -r more than once:
hg clone -r 5 -r 6 -r 7 repo repo2
You can use log and revision sets to determine which other revisions you need to include.
In How do I do a pristine checkout with mercurial? Martin Geisler discuss how to remove already Mercurial commit'ed files using:
hg strip "outgoing()"
But what if I I want to keep my added files which went into "outgoing()" - example:
Two users a and b — starting on the same changeset
User a:
echo "A" > A.txt; hg ci -M -m ""; hg push
User b (forgets to run hg pull -u):
echo "B" > B.txt; hg ci -M -m "" B.txt;
echo "C" > C.txt; hg ci -M -m "" C.txt;
If user b run hg strip "outgoing()" then B.txt and C.txt are lost. hg rollback is not an option since there are two commits.
Can user b revert his files as "locally added - nontracked", then do hg pull -u, which gets A.txt, then handle the add/commit/push for B.txt and C.txt later?
Martin Geisler answered this earlier in the mentioned thread (a comment which I deleted and moved here:
hg update "p1(min(outgoing()))"
hg revert --all --rev tip
hg strip "outgoing()"
hg pull -u
Now user c can finalize his work in the new files B.txt and C.txt and commit+push those.
Other ways to do this?
You could but, by doing so, you are working against one of the biggest features of a DVCS like mercurial, that is, to easily and reliably handle the merging of multiple lines of development as in your case. If user b's goal is to have a line of development with all three changes applied, then the standard way to do that in hg would be to just go ahead and do an hg pull -u which will create a new head containing the change(s) from user a (and any other changes pushed to repo used for pulling) and then use hg merge to merge the two heads, the head containing user b's two change sets and the other containing user a's change set (as pulled). In a simple case like this one with no overlapping changes, hg should do all the right things by default.
$ hg pull -u
[...]
added 1 changesets with 1 changes to 1 files (+1 heads)
not updating: crosses branches (merge branches or update --check to force update)
$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg ci -m "merge"
If there were conflicts between the two heads (i.e. both users committed changes to the same files), there might need to be conflict resolution editing as part of the merge; hg will tell you if that is the case.
Another option is the rebase extension. With your scenario:
A and B start with the same history.
A commits and pushs a change.
B commits two changes, but can't push because of A's commit.
B pulls A's change.
B runs hg rebase and pushes.
Before rebase:
Common ---------------------------- A (tip)
\
B1 - B2 (working parent)
After:
Common - A - B1 - B2 (tip, working parent)