How to make previous commits with EOL issues consistent in Mercurial - mercurial

We have a Mercurial repository with a standard of using Unix-style line endings.
If a user hasn't noticed EOL issues when committing a file - they may be 'helpfully' hidden by the diff tool - then it's a pain to fix down the line unless it's noticed immediately.
Is there a way to use "hg convert" (or similar) to re-create the repository with consistent line endings?

There's no easy way to do it, but you could use hg transplant with the --filter option to reapply those changesets in a corrected form and then hg strip the wrong ones. It'll be enough of a hassle that you'll probably put a pretxnchangegroup hook on your centralish repo to prevent folks from pushing them in the future.

Related

Is there a simple method to keep Mercurial from accepting section of code for commit?

I have a change to a file which I explicitly never want to commit to the repo. (In this case, its a hack around a bug that needs to be resolved by fixing an unrelated codebase.)
Is there a way to mark the change so that Hg will error out if I try to commit it? Ideally, it would be something inline in a comment so that I could choose to not commit that section of code (with TortoiseHg) and still be able to commit other portions.
Currently, I just have the change labelled with a nasty comment block, but it would be a great security blanket if I could tell the repo that this is dangerous code.
An alternative to writing a hook is to commit the change, and move it to the secret phase. This will prevent ever pushing it to another repository. It also allows you to easily apply the change on top of any changeset by rebasing the secret commit.
Use a bookmark or a named branch to make the changeset easy to select.
hg branch externalbugworkaround
hg commit -m "HACK - workaround external bug. DO NOT PUSH"
hg phase -s -f externalbugworkaround
then to move it around
hg rebase --keepbranches -d rev -r externalbugworkaround
As you suggest yourself: the solution is to write a client-side commit hook which parses the file with a regex and errors-out when the code you want to skip committing is part of the commit.
A simple hook which checks for bad file extensions and commit messages is found for instance here - it should be easy to extend to checking a certain file for a specific pattern.

Is there a way to skip a commit when pushing

I had commited an exploratory and buggy changeset locally. The bug has been fixed in the next local commit. Now I want to push the debugged version but in a way that skips the buggy local commit. Is there a way to do this simply.
Short answer: no.
Long answer: you can leave a chain of recent commits out of a push but you can't miss out parts of the chain when you push. This is because mercurial tracks the changes you made at the point of committing and your most recent changeset probably doesn't make sense outside of the context of the buggy one.
Options:
Some people would recommend using the MQ extension to avoid this problem in the future.
Some people would recommend using the MQ extension to strip out both changesets and then re-commit only the fixed version. This can cause trouble, particularly if you've already shared your changesets with anyone.
Some people (including me) would recommend just leaving your repository as it is and pushing both changesets. There's only shame in a buggy changeset if you don't fix it.
4 Some people (including me) would recommend using the MQ extension for folding two consecutive changesets into single before push
5 Some people would recommend using the histedit or colapse extension for folding two consecutive changesets into single before push
You could try this :
Export the commit you want to go through as a patch
Re-clone your repository in a new directory
Apply the patch
Now perform the single commit to your shared repository

How to re-commit last changeset with a different comment?

As I understand it, you can't really fix a comment in Hg. So what I would like to do instead is re-push the exact same changes (or at least "touch" the same files and commit & push again).
The reason this is necessary is because we have a bug tracking and build system that relies on specific comment patterns, and we need to make sure the right files get included in the build, but if I forget to update the bug # in my comment from my last commit, and I accidentally commit and push it under the wrong # because i'm overzealous, how can I re-push those same files again without manually going into each one and adding a space or line break just to create a diff?
To clarify, I can't "rollback" or something; it's already been pushed with the wrong message.
As far as I know, current Mercurial features provide no support for this. After the changeset has been pushed, there's little you can do to un-push it, besides stripping it from the server repo and any other developer's repo.
I guess you you should ask those who set up this workflow in your shop; they should've come up with some exception handlers for it.
We usually just ignore issues like this, and close the bug by hand, making sure the bug links to the correct changeset. If the changeset is really messed up (usually this means bad changes, not a malformed commit message), we resort to stripping.
Since your change has already been pushed you can't use a simple fix, like "hg commit --amend", but you can do something similar. Basically, the following commands re-do the commit with Mercurial's help:
CSET=...the changeset to re-do...
hg up -r "p1($CSET)" # Update the working directory to the parent revision
hg log -r "$CSET" -p > changes.patch
hg import --no-commit changes.patch
hg commit # And use the appropriate commit message.
Then, merge and push.
The only way that I could think of doing this is to commit two more changes, one would be an hg backout of the incorrect revision and the other would be an hg backout of that revision with the corrected comment.
I don't like that idea though and wouldn't recommend it if there was any way to fix the problem in your bug tracking system.

Is there any way of deleting a branch that has been pushed to a repo shared by all developers?

I have accidentally pushed a branch to a repo. Is there anyway I could alter the repo ( and remove the branch )? Closing it is not a solution.
You got a couple of options, none of them easy, and none of them will leave you with a "phew, saved by the bell" feeling afterwards.
The only real way to fix this problem is to try to avoid it in the first place.
Having said that, let's explore the options here:
Eradicate the changesets
Introduce further changesets that "undo" the changes
The first option, to eradicate the changesets, is hard. Since you pushed the changesets to your central repository, you need direct access to the repositories on that server.
If this is a server where you don't have direct access to the repositories, only through a web interface, or through push/pull/clone, then your option is to hope that the web interface have methods for eradicating those changesets, otherwise go to option 2.
In order to get rid of the changesets, you can either make a new clone of the repository with the changesets, and specify options that stop just shy of introducing the changesets you want to get rid of, or you can use the MQ extension and strip the offending changesets out.
Either is good, but personally I like the clone option.
However, this option hinges on the fact that any and all developers that are using the central repository either:
Have not already pulled the offending changesets from the central repository.
Or are prepared to get rid of said changesets locally as well.
For instance, you could instruct all your developers to kill their local clones, and reclone a fresh copy after you have stripped away the changesets in the central repository.
Here's the important part:
If you cannot get all developers to help with this, you should drop this line of thought and go to option 2 instead
Why? Because now you have two problems:
You need to introduce barriers that ensure no developers can push the same changesets onto the server again, after you got rid of them. Note that relying on the warning by the server to prevent new branches being pushed is perhaps not good enough, as developers might have branches of their own they want to push, and thus not notice that they'll be pushing yours as well.
Any work any developer has done based on any of the offending changesets must either be rebased to a new place, or eradicated as well.
In short, this will give you lots of extra work. I would not do this unless the offending changesets were super-critial to get rid of.
Option 2, on the other hand, comes with its own problems, but is a bit easier to carry out.
Basically you use the hg backout command to introduce a new changeset that reverses the modifications done by the offending changesets, and commit and push that.
The problem here is that if at some point you really want to introduce those changesets, you will have to fight a bit with Mercurial in order to get the merges right.
However, there will be no more work for your fellow developers. The next time they pull, they'll get your correction changeset as well.
Let me just restate this option in different words:
Instead of getting rid of the changesets, keep them, but introduce another changeset that reverses the changes.
Neither option is good, both will generate some extra work.
We've ran into a similar problem once, when we had to remove a branch from the server repo from which all devs regularly pull. Backout wasn't an option because the problematic branch had already been pulled by everyone.
We stripped (hg strip from the MQ extension) the branch in the server repo. From now on, if a developer tried to push, he had a message “push creates new remote branches”, even though they didn't actually created any. We created a batch file with the strip command, distributed it among the devs and explained the “new remote branches” is a signal to run the batch file.
This approach takes some time and effort before everybody gets rid of the branch, but it works.
If the 'backout' option described in Jason's comment above doesn't do it for you, you can remake the repo up until the point of your mistaken push using hg convert, which (despite its name) also works with hg.
eg hg convert -r before-mistaken-push /path/to/original /path/to/new
You might have to play with the usebranchnames and clonebranches settings.

Is there a way in Mercurial/TortoiseHg to remove a changeset while keeping its changes in the working copy?

Like the title says. I essentially want a way to make Mercurial "forget" a changeset in the local repository. Obviously, this would only work for changesets which had not been pushed without also reverting the original changeset.
Mercurial doesn't make forgetting anything easy -- no commands that are destructive of history are enabled by default. Without enabling any extensions the easiest way to do this would be:
hg clone -U -r LAST_CHANGE_YOU_WANT your-repo new-repo
and then replace the .hg in your-repo with the one from new-repo.
In this case specifically, I was trying to move changes between branches when the normal merge wouldn't work, so I used MQ, however I wanted the changes to remain in the working copy rather than accidentally getting pushed. It looks like one can do what I wanted with hg import --no-commit, which TortoiseHg does not currently (but should soon) provide any UI for.