Editing the author for specific changesets - mercurial

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.

Related

Mercurial - Working with Queues similar to Shelves?

I've recently started working with MQ as I like the idea of working on isolated patches and committing without affecting the repo until the changeset is refined enough. Before that, I used to work with Mercurial's shelves extension, but found it a bit unstable. What I'm still trying to figure out in MQ is how to keep patches separate from each other and apply them in no particular order, and across different branches. Here's my normal flow -
1. Start working on a new patch:
hg qnew fix-bug-1234 -m "fix bug 1234"
# do some work
hg qrefresh
2. Get a new feature/bug to work on:
hg qpop fix-bug-1234
hg qnew some-feature -m "implement feature X"
# some work on feature X (perhaps in a different branch)
hg qrefresh
3. At this point, I'd like to get back to working on bugfix, and put aside the feature work. I thought it's as simple as:
hg qpop some-feature
hg qpush fix-bug-1234
# wrap up bug fix
hg qfinish fix-bug-1234
# get back to work on feature
However, MQ seems to always use the latest patch created in the series, and apply it regardless of the qpop/qpush command I'm using. I should note that the files I work on are completely separate as well (though they can sometimes be the same).
Am I missing something here? Should I be using hg qqueue for this? Thanks.
You could use guards. They allow you to maintain an ordering of patches without rearranging your series file, and selectively apply only a subset of patches, still in a stack-ordered fashion.
An example in your case would be:
hg qnew bugfix
# ..hack hack..
hg qrefresh
# want to switch over to working on some feature now
hg qpop
hg qnew feature
# ..hack hack..
hg qrefresh
At this point, you're in a situation where patch feature comes before bugfix in your stack. Now you can use guards to select one or the other, and switch between the two:
hg qpop -a
hg qguard feature +featureguard
hg qguard bugfix +bugfixguard
If you want to work on feature:
hg qselect featureguard
hg qpush
applying feature
now at: feature
If you want to work on bugfix:
hg qpop -a
hg qselect bugfixguard
hg qpush
applying bugfix
now at: bugfix
Note that since you selected the positive guard bugfixguard, MQ leap-frogged over feature (because it's positive guard was different than the one selected) and applied the patch bugfix instead (which did match the selected guard).
Some useful tools when working with guards are hg qseries -v, which will display a G instead of the usual U for a guarded, unapplied patch, and hg qselect -l which will display the guards associated with each patch.
Execute hg qpop -a to remove all patches from the stack
Execute hg qpush --move some-patch to apply "some-patch" without applying whatever other patches may be before it in the patch stack
No, you aren't missing anything. The mq extension does make a pretty strong assumption that patch queues are linear. If you're going to be creating multi-patch features/fixes then qqueue would work… But if your features/fixes are just single patches and you want to be able to apply one with out applying the others, it might be easier to just re-arrange .hg/patches/series (which stores the order that patches will be applied).
I do this (and hand-editing patches) enough that I've got a shell alias:
alias viq='vim $(hg root)/.hg/patches/series'
Alternately, if you don't mind applying multiple patches at the same time, you could use qgoto:
$ hg qser
0 U bug-1234
1 U feature-4321
$ hg qgoto feature-4321
$ hg qser
0 A bug-1234
1 A feature-4321

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.

mercurial push certain revision

I have searched here, but haven't found any question related to this. I got a problem like this in mercurial:
I manage open source project in bitbucket, so i have clone of the source code in my local. But I also using that project for my own live site, so I made 2 clone of bitbucket repo
Bitbucket Repo
|
==local_clone1
|
==local_clone2-> commit1 => commit2 => commit3
(personalization) (bug fix) (add feature)
The question is, I want to push commit2 and commit3 back to local_clone1, so later on I can push to Bitbucket repo. But don't want to push commit1, since it has my personal data.
Wondering how we do that in mercurial?
This can be done without too much difficulty in this case. See Removing history in the Mercurial guide for more information.
Here's the basics of what you'll need to do:
Go to local_clone2
Get the revision number (hg tip will show you) from the current number. We'll call it 731.
hg export 730-731 > ../local_clone1/changes.diff (or wherever you like)
Go to local_clone1
hg import changes.diff
You may need to edit things manually; refer to that guide for more info in that case.
Here are a couple of options:
backout
Given a history constructed as:
hg init db
cd db
echo >file1
hg ci -Am clone # rev 0
echo >file2
hg ci -Am personalization # rev 1
echo >file3
hg ci -Am bugfix # rev 2
echo >file4
hg ci -Am feature # rev 3 <tip>
Then if the current working directory is the tip, the following commands will "undo" the personalization revision:
hg backout 1
hg ci -m backout
The advantage is history remains immutable, but shows the addition and backout of the personalization changeset.
Mercurial Queues
With the mq extension, history can be edited to remove a changeset:
hg qimport -r 1:3 # convert changesets 1-3 to patches
hg qpop -a # remove all patches (can't delete an applied patch)
hg qdel 1.diff # delete rev 1's patch
hg qpush -a # reapply remaining patches
hg qfin -a # convert all applied patches back to changesets.
The advantage is the personalization changeset disappears. The disadvantage is the changeset hashes change due to the history edit, so this should never be done to changesets that have already been pushed to others. There is also the risk of a mistake editing history.

Transplanting into one changeset

I'm trying to move changes from a couple of changesets into one changeset on the other branch. There are other changes in between that I want to skip, so I don't want to simply merge everything.
hg transplant moves the changes correctly, but now I'd like to flatten them into a single commit. How can I do that?
You can fold them by
Backup the repository, a failure during the process can destroy data
transplant the desired changes to the target branch
transform them there into a mercurial queue (hg qimport -r first-to-fold-rev:)
fold them into one patch (hg qpop until the first patch is applied, then hg qfold <<patch name>> the following patches into this one)
Edit the commit message (When there are NO OUTSTANDING CHANGES hg qrefresh -e)
apply the single patch to your repository (hg qfinish -a).
When there are further unfolded patches:
hg qpush until the head patch
hg qfinish -a
Review the new repo state (hg glog/hg incoming)
hg rebase has an '--collapse` option. I think this is what you are looking for.