Hg: delete latest commits [duplicate] - mercurial

This question already has answers here:
Is there any way to delete local commits in Mercurial?
(10 answers)
Closed 8 years ago.
I've used Git in the past and I'm a Hg noob:
I have following repository structure:
o [> default] commit A
|
o commit B
.
.
.
o <a-tag]
|
I've updated to the commit with the a-tag and committed a few other commits. Now I have
o [> default] commit C
|
o commit D
|
| o [default] commit A
| |
| o commit B
| .
| .
| .
| /
o <a-tag]
|
Now (before pushing) I realize that I had my commits commit C and commit D based on the wrong commit. How can I go back to the initial state (without having to re-clone the repository) dropping these commits commit C and commit D (pendant to git reset --hard a-tag)?

You can use 'strip' to permanently delete commits and all it's descendants. In your case you need to specify the id of "D" revision:
hg strip -r D
Note: mq extension must be turned on:
[extensions]
mq=
Mercurial backups bundles of the stripped changesets in .hg/strip-backup so this operation is rather safe.

You say without cloning, and I'll get to that but first let me point out that doing this:
cd ..
hg clone -r -2 yourrepo yournewrepo
is an instantaneous action that gets you a new clone, locally, without the last two commits in your old repo. Because it's a local clone it uses hardlinks (even on Windows) so the repository takes up no additional diskspace.
That is the classic Mercurial solution. Mercurial was built with the idea of an immutable history. If there's something in the history you regret you commit its inverse (which is what backout does), so the history shows the error and its correction -- like a scientists log book. If you can't/couldn't abide having it in history you'd do a clone that excludes it like I showed above.
Not everyone can be quite so... hardcore... about their history, so lots of extensions have shown up that will modify history but they have to be specifically enabled. In your case the rebase extension, which you already have installed (it comes with Mercurial now), will do exactly what you want. You just need to enable it in your ~/.hgrc and then reparent D onto A. If you really just want C gone the strip command from the mq extension will do that. It also ships with Mercurial.

I would just clone from the appropriate point and delete the old repo.
Without cloning consider hg backout to undo first C and then D, or, if this is your ultimate goal hg rebase to move both C and D to the commit A point.

Backout C + backout D will remove these 2 commits, but add additional 3 (backout+backout+merge). "Clean" remove from history may be
Histedit extension ("drop" command)
MQ extension (convert changeset to mq-patches /first steps/ and drop mq-queue)
If you want only change wrong parent to correct, you have to use rebase, as #chill mentioned

Related

how do I push most recent commit in HG

I have done some local commits.
But I want to push the most recent ones like 4977 and 4978 excluding the previous ones.
4948 local commit 1 is the ancestor of all commits
Can some one tell how do we do that in HG
4978 local commit 4
|
|
|
4977 local commit 3
|
|
|
4976 local commit 2
|
|
|
4948 local commit 1
Mercurial repositories are intended to have immutable histories, so out of the box this is not possible. However, there are workarounds for this.
Possibly the easiest way to achieve this would be with the histedit extension. You would need to enable it by modifying your .hgrc (or mercurial.ini) with the following
[extensions]
histedit =
Then you can run the histedit subcommand from the command line and tell it to look back as far as the changeset you're concerned about...
hg histedit 4948
This will pop up a text editor with the word pick next to each changeset. Change pick to drop for the changeset you don't want any more, save, and exit, and the problem changeset will be gone.
Note that this will remove the changeset from your local repo, in addition to prevent it being pushed to the remote!
You cannot push a commit with out pushing all the ancestor commits as well. However, you can "fold"/"collapse"/"squash" commits together to get rid of the ancestor commits you don't like. You use the standard histedit extension for this.
Simply run
$ histedit 4948
and you will see an editor open up. That edit contains a file that will serve as the instructions for histedit. By default all changesets are left unchanged, but you can change the keyword at the beginning of the lines to change this. Also, you can reorder the lines to reorder the corresponding commits.
Changing the keyword in the beginning of a line to fold will tell histedit to combine the commit with the previous commit. That way you can change your history to
4978 local commit 4
|
|
|
4977 local commit 3
|
|
|
4948 local commit 1
and thus "fold" the changes you made in your local commit 2 into local commit 3.

Mercurial moving commits in another branch

My coworker accidentally made two commits in the default branch instead of creating new his own development branch.
How can I change this situation and moves these two commits to a new branch?
Imagine the following scenario:
D
|
C
| "I want to move C and D here"
B/
|
A
Steps:
hg update B
hg branch "mybranch"
hg commit --message "Create my branch"
hg update mybranch
hg graft -r C
hg graft -r D
hg strip -r C (this should be the revision C had originally)
The strip command is provided by an extension that you need to enable. You can follow a guide on how to enable it on the Mercurial Wiki.
hg update default
A major question
Have the accidental commits reached other repositories or is it just in his own? If so, you can skip to the section below 'Maybe the cat is still in the bag' otherwise you may have a fair bit of work to do.
You are not alone
See here for more discussion on how to correct the problem elsewhere on Stack Overflow. What is described is the 'proper' way to to it
export a patch
create the branch
import the patch
delete the earlier commits.
Maybe the cat is still in the bag
If the changes are only in the local copy, then a simpler solution is to
create the new branch
switch to it
merge the changes onto that either with your fav merge tool (go Meld) or with hg graft
use the hg strip command to delete the changes on the old brach
push the changes to the world
pretend like nothing ever happened, whistle a happy tune ...
The two answers above are both correct but, assuming one has not yet pushed the commits, there's a third way.
I just successfully used the rebase command to move a string of commits to a topic branch I had forgotten to create in the first place.
I first updated to the revision from which I wanted to create the branch on which my commmits were supposed to be, then I rebased the earliest of my commits from the wrong branch on this new one and ta-da, done.
Takes more time to explain it than to do it with TortoiseHg or even the command line, really.

Mercurial Reverting Back, then Reapplying Changesets

I have commits A, B, C, D, and E. I realize that something very bad happened in commit B, so I want to revert back to A, make the change correctly this time that screwed up B before, and then reapply C, D, and E automatically.
You may be wondering why I don't revert back to B and make the fix there, then remerge back in to E (is this ever a good idea?). The reason is not well understood by me, but it has something to do with the problem occurring in a set of special visual studio files (that should only be edited via some GUI screens in visual studio) that don't play well with simply correcting the file after an error occurred... I would give more details if I knew them
Just make a backout of what you did in B and commit it as F. This way, history will be intact, and your peers will get the change without having to know about it.
If B is a service release, do make the change there and merge it into F afterwards.
This can be done using Mercurial Queues (mq). You want to:
Import changesets B through E to mq
Unapply changesets C through E
Fix changeset B and refresh the patch
Reapply C through E
Finalize the patches
This is done as follows:
cd <project>
hg qinit
hg qimport --rev B:E
hg qpop --all
hg qpush <patch name for B>
...fix the problems you found in B
hg qrefresh
hg qpush --all
hg qfinish --applied
This all assumes that B through E have not been pushed to any public repositories. If they have already been pushed, then your best bet is to simply fix the problem in a new changeset (F).
You can also use the HisteditExtension (instead of MqExtension). MqExtension is much more powerful, but it's also much more complicated, I think. HisteditExtension is a bit more like git rebase --interactive.
# Ordinarily it would be something like (I'd normally do -r -5, instead):
hg histedit d0844102a010
Your text editor will be opened with a file that looks something like this:
pick d0844102a010 A
pick a9448f0ba534 B
pick b754f9f2513b C
pick 736f7f2363ff D
pick 05bb58f48597 E
# Edit history between d0844102a010 and 05bb58f48597
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# f, fold = use commit, but fold into previous commit
# d, drop = remove commit from history
#
Each line corresponds to a commit. The first word refers to a command to be applied to that commit. The default "pick" just keeps the commit as is, unchanged. Use "edit" to make changes (including commit log changes), "fold" to combine it with the previous commit, and "drop" to delete it entirely.
In your case, you'd probably just need to change the first line to "edit".
Remember that you must use hg histedit --continue instead of hg commit (if you're "editing" or if there's a merge conflict). :) If you get conflicts and things aren't looking good and you just want to cancel then you can use hg histedit --abort.
# Fix up files...
vim foo bar baz
# Finished; apply the changes (and pray for a clean merge ;).
hg histedit --continue
Edit history at own risk, of course. I recommend that you create a backup tarball or zip of your source tree prior to editing history until you're familiar with the commands.

Why can't I rebase on to an ancestor of source changesets if on a different branch?

I would like to know why the following pattern is not possible.
Having created a local feature branch (minor_feature - not intended to be shared with the world) I would like to rebase the work on it on to the tip of a well known branch (stable). However I have discovered that rebase finds nothing to be rebased in the case where stable has not progressed since branching away from it.
I appreciate that this breaks the rule that the destination of rebase can not be an ancestor of the source but can't work out why this should be prohibited in the simple case shown. I also understand that, branches aside, the topology would not actually change during the rebase. But given that the branch names are indeed significant to the topology, it only seems to be a special case in that stable has no further revisions commited to it. With a single extra revision on the tip of stable (say pulled in from elsewhere) I can of course perform the rebase
o branch:minor_feature
| rev:4
| changeset:746d8191aa5d
|
o branch:minor_feature
| rev:3
| changeset:520f565ba7f2
|
# branch:stable
| rev:2
| changeset:64e7c753c090
|
o branch:stable
| rev:1
| changeset:3dc55a5c9971
|
o branch:stable
rev:0
changeset:fbf1f426945c
$hg rebase -b minor_feature
nothing to rebase
--
Thanks
Chris Gorman
Rebase is strictly for changing ancestry of changesets. As you've observed, you're not changing ancestry here. Branches aren't included in the ancestry computation.
I'm not 100% sure what you're trying to accomplish. If it's to effectively remove the branch, then as long as you haven't pushed, you can likely use the MQ extension. Import the changesets, pop all. Ensure you're updated to the stable branch (which it should be by default), and push them all back on.
They should now all be on the stable branch.
You can do this with the convert extension. You would use a branchmap to rebase minor_feature to default. That file (we'll call it alldefault) would look something like this:
minor_branch default
Then the command would just be:
$ hg convert --branchmap alldefault oldrepo newrepo
When it finishes, newrepo will have the named branch "rebased" on top of the default branch.

TortoiseHG: cannot partially commit a merge

I tried to merge two heads in Mercurial. After merging, I didn't commit and did some more changes. Then I tried to commit and got the following message:
abort: cannot partially commit a merge (do not specify files or patterns)
I'm using TortoiseHG as visual shell, and Beyond Compare for comparing and merging. And I'm relatively new to all of them.
What should I do to finish commit successfully?
Mercurial/TortoiseHg is correct in telling you that you should not partially commit a merge. Partial means that you do not commit all files at once.
The underlying reason for this message is that is gives you the wrong results. When you merge two changesets in Mercurial, you are creating a new changeset with two parent changesets. This merge changeset shows others how you want everybody else to combine the two changesets.
Let us imagine that you start with changesets A and B and want to merge them. This creates a graph like this:
... --- [A]
\
[M]
/
... --- [B]
Pretend that we added the line A! to a.txt in the A changeset and that we added B! to b.txt in the B changeset. Just two independent changes that does not conflict. If Mercurial allowed you to do a partial commit, then you could do this:
hg merge
hg commit -m 'Added A!' a.txt # creates M
hg commit -m 'Added B!' b.txt # creates M'
and the result is this graph:
... --- [A]
\
[M] --- [M']
/
... --- [B]
If you look at b.txt along the path B, M, M', then you will see that the line with B! was introduced in B, removed in M and reintroduced in M'!
This is not what you want from a merge changeset: a partial merge throws away changes from one branch just to introduce them again in a followup commit. Mercurial trusts you when you create M: it really believes that M contains the correct mix of A and B. In particular, if the B! line is removed in M, then it will remain gone when you merge M with other changesets.
So Mercurial is trying to protect you from creating a bad history by not allowing partial merges.
I think you have aliases in hgrc file. Try to remove [alias] section and commit again.
What should I do to finish commit
successfully?
One of the benefits of Mercurial (or git or any other DVCS) is that you can perform a commit at any point in your development process and it will be both fast and private. It will be fast because you should be committing to a local copy of the repository residing on your hard drive, and it will be private because no-one will see your change set until you push them to the server (or other master repository).
Therefore, to partially answer your question, the appropriate thing to do would have been to commit the merge without your addition changes, and then apply and commit your next wave of changes. If you are using TortoiseHG to peform the merge it will actually prompt you to commit the merge before leaving the GUI because this is the intended HG workflow.
That being said, I made some changes on a named branch (ie: new head), merged it back into the default branch, exited the TortoiseHG GUI without committing, made some more changes, and then committed with no problem. I will ask some clarifying questions below your original inquiry.
I had this problem because I had deleted some files. I reverted the files to restore them, then was able to commit. I then deleted the files and did a second commit.
I had the same problem and I was NOT specifying any files and using command-line.
The problem was the [default] section in my .hgrc
[defaults]
commit = -X project/web.config
So it added specific files to every commit-operation by default.
Review your defaults section for potential problems.
I had the same problem and the command I gave was
hg commit -m Merge with 1234
I figured it out after sometime that the commit message "Merge with 1234" has to be given in quotes as the command takes "with" and "1234" as file name params.
please check it in your case.