Pushing single changeset in Mercurial when multiple are available - mercurial

I have 5 outgoing changesets available to push from my local Mercurial repo, and I only want to push one of these at this time. This one changeset lies in the middle of all available.
For example I have the following revisions:
6639
6546
6545
6544
6543
and I only want to push 6545. Any easy way to do this?

You can only push the consecutive list of changesets up to the required.
So
hg push -r 6545
will push 6543..6545.
And you cannot push just 6545 because without preceding changesets its changes make no sense.

You could use the Mercurial Queues extension to do this. You may need to enable the mq extension which is detailed on the linked page.
You would import all the revisions into the queue, pop them all off the stack and then apply the one that you want before pushing and then applying the rest. Something like this:
> hg qimport --rev 6639
> hg qimport --rev 6543:6546
> hg qpop --all
> hg qpush --move 6545.diff
Here you might have to resolve conflicts
> hg qfinish --applied
> hg push
> hg qpush --all
Again, might need to resolve conflicts here.
This has left your repository with revision 6545 applied and pushed (but with a different revision number now) and the rest of your changes applied and not pushed.

What you want is not possible. A revision must put a repository in a definite state, but if you could push 6545 and the remote repository updated to it, it would not include the changes from earlier (not pushed) revsets. This goes against the core design of mercurial. What you can do is:
a) distribute a diff (patch) that contains the same changes as rev 6545. You can do this via hg diff or in other ways, but applying the patch is not inherently connected to your rev 6545: it is a separate revision that "happens" to make the same changes. If you're lucky, they can be merged in the future without problems. Or
b) rewrite your history, temporarily (with the mq extension) or permanently (with the help rebase or other extensions) so that 6545 is placed immediately after the already-commited revisions. You can then push it like any other revision whose ancestors have already been pushed.

Related

Backout unwanted changes and make a patch out of them

I'am collaborating with someone on remote repo. We realized that changes I made should be removed out of repo. But those changes are in many changesets and mixed with someone's changes.
We decided to remove my changes just before I commit another changeset. So I've made a patch out of uncommited changes and qpop it.
Now I want to backout rest of my changes out of remote and selectively make patch out of those changes leaving my colleague changes untouched.
Moreover I want to have diffs from new patch with diffs from patch_ive_made_before in one patch. So in other words - I'd like to have one patch out of 2 different changesets. Do I have to do it manually?
Then after I do it, I will commit/push cleared changes into the repository.
How this could be done with Mercurial Queues?
You can make a patch that is the reverse of a previous change using this command:
hg diff --change NODEID_YOU_REGRET --reverse > undoes-what-you-regret.patch
That patch could be put in a mercurial queue using:
hg qimport undoes-what-you-regret.patch
Were I doing it, though, I'd skip mq entirely and just do:
hg backout --rev NODEID_YOU_REGRET
that will create a new head, which you can hg merge into any line of development that's a decendent of the original change -- i.e.: anything that has that code.

Editing the author for specific changesets

At the moment I am looking at transitioning from subversion to Mercurial at work, and as such the Mercurial repository is not yet published.
I have used the authormap argument to transform our usernames to the Mercurial format, which went fine.
Unfortunately two people have been commiting under the same name. The repository is not very large, so I would like to change the authors to match the right people. For that reason I would like to ask:
Is there any way to change the author for a specific changeset, or a list of changesets?
You can use the bundled extension Mercurial Queues (MQ) to change commit authors. Note that MQ will only work as long as history is linear. If there are branches you need to first rebase them off to a temporary side branch, and then after editing rebase them back.
First qimport the changes up till the first changeset you want to modify:
hg qinit
hg qimport -g -r <first-revnr>:tip
Then use qpop or qgoto to navigate to the respective changesets:
hg qgoto <revnr>.diff
And then use qrefresh to change the user info on the currently active changeset:
hg qrefresh -u "Some User <user#example.com>"
You can verify with hg log whether the user was correctly updated. After this, repeat for all other changesets.
When you are done, qpush all patches and use qfinish to finalize the repository.
hg qpush -a
hg qfinish -a
You could as well use the evolve extension. After setting up the extension
hg amend -U && hg prev
for a stack of commits and then hg evolve --all at the end.
Evolve introduces a meta-graph that says which commit replaces which commit.
So when we do hg amend -U a bunch of times, we create commits with a different author that replaced the old commits. hg evolve --all the will use the replacement information to figure out where to move commits that were based on our pre-replaced commits.
Credits to mercurial developers on IRC #mercurial.

Can changes made by strip be reflected in the public repo?

Let's say I have this:
hg clone public_repo my_repo
touch a b c d
hg add .
hg commit -m a a
hg commit -m b b
hg commit -m c c
hg commit -m d d
hg push
# let's say revX is the revision that added a
hg strip revX
In my repository's history, the commits are gone. However, if I try to do a push after the strip, it tells me no changes found. Can the strip be applied to the public repo?
EDIT: the question is just hypothetical :). I am not in this situation, I just thought it would be interesting to find out how this works.
You need to run hg strip there. If it's bitbucket repo, you can do it from the admin panel. If not, SSH.
This is not possible. You have to strip the public repo as well.
hg strip just takes away changesets. It does not perform an "adding" operation which could be pushed.
In the exact example you provide, you could just hg rollback on the public repo.
Let me pretend you're asking a slightly different question: I've stripped part of my repository history, how do I propagate this change to other dev's repositories?
Mercurial offers no way of propagating stripping in the same way it propagates adding changesets. So you have to come up with your own way.
Bitbucket, for example, has an updates list (on the repo summary page, if my memory serves me well). If you do a strip, Bitbucket displays there something like this:
Changeset 12345abcdef was stripped from the repository, please run hg strip 12345abcdef locally.
When we had to propagate stripping of part of an old branch in our shop, here's what we did:
Stripped the changesets on the server.
Created a batch file named strip.bat on the default branch of the repo containing the command we'd run on the server, i.e. hg strip 1234567890.
Told everybody that whenever they cannot push because “push creates new remote heads” for no apparent reason, this means they should run strip.bat.
In case we ever need to strip something again, we just add another hg strip in the batch file.
P.S. Yes it's better not to strip, e.g. use backout to commit inverse changesets. Sometimes that's not an option: if you mistakenly merged branch a into branch b when you wanted the merge b into a, you're trapped. Even if you backout the merge changeset on feature, the merged changesets from a are already marked as merged, and you'll have a hard time doing another merge of these branches.
The correct and safe way to remove unwanted changes that made it to the wild is to hg backout them.
Sometimes it is not possible to strip or backout a change, for example if it was a merge revision and you don't have admin access to the server. One method that does work is to branch the last good revision and then close the bad head.
hg up badrev^ (Go to the revision before the bad one)
touch dummy && hg add dummy && hg ci -m 'dummy' && hg rm dummy && hg ci --amend -m 'Fix accidental merge' (Create a second head with no changes from the good revision)
hg up badrev (Go to the bad revision)
hg ci --close-branch -m 'Close bad head' (Close the bad head)
hg push

Placing recent commits in a separate (named) branch in Mercurial (Hg)

If I have several commits made to the default branch since the last push, is it possible to go back, and move those commits into a separate named branch?
That is, I have:
A--B--C--D
and I want:
A
\
B--C--D
I hope this makes sense?
Take a look at the Transplant extension.
But personally, I'd do it using MQ, like so:
# assuming revs 1 and 2 are the ones we want to move
hg qimport -r1:2
# qimport creates a patch for each changeset
>hg qapplied
1.diff
2.diff
# pop the patches, to save for later
>hg qpop -a
popping 2.diff
popping 1.diff
patch queue now empty
# switch branches
>hg branch my-branch
marked working directory as branch my-branch
# push our saved changesets, essentially rebasing on the new branch
>hg qpush -a
applying 1.diff
applying 2.diff
now at: 2.diff
# make the patches part of permanent history
>hg qfin -a
You could probably also bend the Rebase extension to suit this purpose, if you prefer.
If the commits are still in only your local repository and have not been pushed to any other one, then yes, you can re-arrange them with fairly minimal trouble. If they have moved beyond just your local repo, however, you will run into a lot of trouble.
To re-arrange commits, you want to use the MQ extension. Here's a tutorial, since it explains things better than I could here.

How to revert a Mercurial hg pull?

If you do an hg pull and then an hg update (or an hg merge), is there a way to back this out? Ie: revert your repository to the state prior to doing the hg pull?
I believe you can do hg update -r n where you would specify the changeset prior to the pull as n. Though I'm guessing this will still leave the changesets in your repository but this isn't really what we want. ??
hg strip will remove revisions from a repository. Like all powerful commands, its dangerous, so be careful.
https://www.mercurial-scm.org/wiki/StripExtension
Also see:
https://www.mercurial-scm.org/wiki/EditingHistory
If you catch your mistake immediately (or reasonably soon), you can just use hg strip REV to roll back the latest (one or more) changes. ...
Ok, you can't rollback because you've done a commit. What you can do is use 'hg strip' which is part of mq (after 2.8 strip is in it's own extension), or use mq to remove the changes. Either way I suggest you do everything on another clone, just in case.
To do strip, update to a revision that you want to keep, and then
hg strip <REV>
where <REV> is the first revision you want to remove. It will remove that one and all decendents (including your merge commit).
Alternatively you can
hg qnew (if you don't already have a patch queue)
hg qimport <REV>
which will import a single revision into the patch queue. You can then add more, and then use the mq commands to edit, rearrange, delete, or whatever you want to do with those revisions. qdel deletes the current patch.
Edit: Obviously, you'll need to enable the MQ extension for both of these, unless you're using 2.8 or later. In that case strip is in the strip extension, and mq in the mq extension. Both are shipped with the standard installation.
hg --rollback can be used to undo the last transaction so as long as your hg pull is still the most recent transaction then you can use that. This command should be used with care though. See here for some more details.
you can:
hg update -C <version>
see the mercurial FAQ.
If you want to remove all traces of the pull form your history then you need to use an extension as Bert F suggests (the philosophy in mercurial is to never change history)
if you dont mind history containing your mistake you have two slightly different options hg update -C -r which will create a new branch at the version you specify or hg revert -r which will stay on the same branch but create a new uncommited change undoing everything.