Close head without committing any change - mercurial

I'm working on a project which is using mercurial and it's gotten into a bit of a mess with a number of heads which for all intensive purposes are dead.
I want to kill off these heads and bring the commit graph back to a single line.
I've been told there's a way to merge branches but at the same time ignore any file changes, so essentially just merging the tree, but I can't seem to work out the command set.
Is there a way to do this, kill off branches by doing merges and ignoring the file changes? Or alternatively is there a way to bring in the graph again without the changes (which are not massively irrelevant in the project)?

If you are using TortoiseHg and named branches, you can select the branch option in the commit dialog to close a branch and it will allow you to commit without having an actual file change.
It will still leave you with a head, but it will be marked inactive.

I think this is just what you're looking for:
Keep My or Their files when doing a merge
It'll create new merge changesets that close down the "other" head w/o taking in any of its changes. You won't end up with a linear history but you'll end up with a single head.
Other inferior answers include using hg strip or hg clone -r to eliminate the heads/anonymous-branches you don't want. They're inferior because (a) if other clones exist you can't strip it doesn't work at all and (b) they throw away history which is the opposite of good version control practice -- even work you don't think you want now may be valuable someday.

Related

Incorporating external changes using Mercurial and TortoiseHg

I'm looking for advice on how best to organize my repository to handle outside changes. And, I have a simple user question on creating a branch in TortoiseHg. This is my first time setting this sort of thing up, so I'm having trouble figuring out the most straightforward way to handle it.
I have a website set up on a service. The theme we're using is based on one of their examples. Occasionally, they'll update the theme we're based on. And, most of the time, I would like to incorporate most of those changes.
The part that is tripping me up is that I don't necessarily want to incorporate all of their changes. So, is the correct way to do it to create two branches? One that is canonical version, straight from them, containing only their edits? And the other is our release branch, that we merge in only portions of their changes?
Will the canonical branch persist? Or, does it come into existence only when they do a new dump, and then I do a manual merge back into my release branch with the changes I want to incorporate?
If it's persistent, is there some way to use TortoiseHg to create the branch back at the root? Or, do I need to dig into the command-line syntax to do that? I know this is a one-time thing for this project. But, I'm looking for advice on how to do this in other software situations, where I want to go back to an earlier version to make a patch. I'm sure there's a tutorial for exactly this situation, but I wasn't able to come up with the correct search phrase to find it. At least, not using TortoiseHg.
If upstream theme is also version-controlled (in any SCM, supported by Mercurial), two long-term branches with grafting some subset of changesets from VENDOR to MY is, naturally, fast and easy way (another possible solution is MQ-patches on top of branch with vanilla theme, but it's slightly harder way)
If original theme not versioned, you can just grab sources from time to time, edit (incorporate own changes, remove unwanted) and commit this own changeset into single-branch repository
is there some way to use TortoiseHg to create the branch back at the root?
I can not recall or find (with quick-search) nice & obvious way to create branch in GUI-way (i.e. big button on toolbar "Branch"), but you can create branch at commit stage (anyway, branch doesn't exist while at least one changeset in this branch isn't committed). In order to create branch, starting from <some old> changeset, you have:
Update to <some old> changeset (RClick - Update...)
Commit (without changing anything), but in commit dialogue use "Branch" button on commit-toolbar (see 1) in order to change old branch-name to some new (see 2)

Mercurial: abandoning multiple, contiguous commits, on the `default` branch

Requirement
I'd like to abandon a line of development on the default branch, winding back to a revision from about 15 change sets back, and have default proceed from there.
My setup
This is a solo development project with one other guy testing infrequently. I push (frequently) to bitbucket for backups and sharing with the tester. Several of the changes I want to abandon are pushed to BitBucket.
Options
Any of these would be fine…
The abandoned change sets to continue to exist in the repo. It would be nice if they could live on their own branch abandoned-experiment-1, say, that I can close and ignore, but this would need them to move on to a retrospectively created branch (which seems like it would be an awesome feature?).
Some kind of merge to happen where I add a new revision to default that is the rollback to the revision I want to continue from.
The change sets to be destroyed, but I suspect there's no way to achieve that without replacing the BitBucket repo and my tester's repo, which I'm not keen on.
I'm not too sure how to evaluate which options are possible, which is best, or whether there are other, better options. I'm also not sure how to actually proceed with the repo update!
Thank you.
You do have several options (Note that I'm assuming that you are dispensing with all changes in the 15 or so revisions and not trying to keep small bits of them):
Easiest is kinda #2: You can close anonymous branches just like named branches; Tag the tip first with abandoned-development if you wish; hg update to the point you wish to continue from; and continue to code as normal. (You may need to create the new head for new development before you can close the old one. I haven't tested it yet.)
Regarding #3: Based on my cursory read, it does appear that bitbucket has a strip command. If you (both locally and on bitbucket) and your tester strip the offending changesets, you can carry on your merry way and pretend like they never existed.
Achieving #1: If you are definitely set on getting them to a named branch, you could strip them at the remote repos and then hg rebase them onto a new branch locally and then close that branch.
Personally, I try not to mess with history when I can avoid it, so I'd go with the easiest.
Mercurial now has (yet experimental) support for changeset evolution. That is you are able to abandon or rebase already pushed changesets. Internally this works by hiding obsolete changesets (i.e. practically nothing is stripped, only new replacement revisions are added to the history, that is why it works across multiple clones).
To extend #Edward's suggestions, you could also update to the last good revision, continue to commit from there and then merge in the head of the bad changesets using a null-merge:
hg up <good-revision>
... work ... commit ...
hg merge <head-of-bad-revisions>
hg revert --all -r .
hg commit -m 'null-merge of abandoned changesets'
This may be what you thought of as option 2.

Mercurial: Automatically tagging a build

In a mercurial set up, I'd like to automatically tag certain builds based on continuous integration scripts. For example, a tag such as branchName-buildId whenever a build of a branch is deployed, or perhaps latest-stable whenever a build passes all integration tests.
However, I'm worried that the straightforward approach of simply calling hg tag will cause problems:
Some tags may be duplicate - i.e. latest-stable. I don't really care which build gets tagged in this situation, but I don't want any conflicts because a script can't resolve those.
Tags cause commits. However, this means that those commits need to be pushed and they need to be robust in the face of concurrent pushes by humans and other scripts. In particular, the automatic push can create additional heads, which is Not Good. But by the time the additional head is detected (at push) the local tag commit has already happened, and even though the new heads are likely trivially mergeable, sometimes tags cause conflicts.
How can I automatically let the CI server tag a build robustly? Here it's more important that the end result is consistent (i.e. that it doesn't mess up the CI server or the repo), and it's less important that tags are reliably applied in the face of duplicates or conflicts (which should be very unlikely anyhow).
I think you're right to be cautious. Robots aren't always the best citizens, and can often do silly things.
What you end up doing depends on what you see the tags being used for. For example, if you only see the CI system using them, then I'd suggest keeping them local. No pull/push/merge issues at all.
Some tags may be duplicate - i.e. latest-stable. I don't really care which build gets tagged in this situation, but I don't want any conflicts because a script can't resolve those.
If a tag is already defined, and you call hg tag again, it will fail unless you force it, but what this does is add a newer, later definition of the same tag, and the latest one wins. On one hand this is good, because the merge is simple, but think about the case when you do:
hg update -r latest-stable
hg update -r latest-stable
hg update -r latest-stable
hg update -r latest-stable
Each time you'll update to the version you'll get a version before the tag was made (as normal), and at that version latest-stable will point to the previous latest-stable. The result is that this sequence of commands will move you back through time.
Hence I'd say it's better either to have unique tags (i.e. stable-2013-02-18) or tag in two commits; One that removes the old tag, and one to add the new one.
hg update -r latest-stable # You're now at the commit that removed the tag.
hg update -r latest-stable # This one will error because tag doesn't exist
Tags cause commits. However, this means that those commits need to be pushed and they need to be robust in the face of concurrent pushes by humans and other scripts. In particular, the automatic push can create additional heads, which is Not Good. But by the time the additional head is detected (at push) the local tag commit has already happened, and even though the new heads are likely trivially mergeable, sometimes tags cause conflicts.
The CI robot should tag; pull; merge (if necessary); push. If the merge fails, don't push, raise an alarm. If the push fails (i.e. there's been more changesets in the time it took to merge), pull and merge again. I'd just make sure your script is very explicit about the revisions it's merging. This process should leave you with no extra heads.
I believe Mercurial treats the .hgtags file differently for merging because it knows about the content, so conflicts should be very rare. Also, tag commits are, in general, easy to merge because all that changes is .hgtags, so a merge from the CI head should never conflict. The only reason it could is because someone else is using the same tag names as the CI server, and if they are doing that then they need to have honey poured on their keyboard so they can do any more damage.
The situation I can see causing problems is if you're doing CI tagging on multiple heads with the same tag names. e.g. Development and release branches both have CI run on them, both have tests-clean tags assigned, but to different revisions, and are then merged later. Solution is, don't do that.
Hope some of that is helpful.
If you care about history of builds then consider creating a named branch just for the build process. In Mercurial all tags from all branches are visible in whole repository.
If you don't care about history bookmarks should do the trick. Build process can set bookmark latest-stable after tests are run and then execute hg push --bookmark latest-stable to push that bookmark to the server.
In either way take you have to take care that you don't run tests on revisions which child has already been tested. Mercurial revsets are very powerful query language and should help.

How to delete permanetly a change set from Mercurial?

Late last night I ended up checking in the production login details into the repository. As I am right now the only developer working on this, it is not a big deal but in future it is not great having the production details exposed.
What I ended up doing was going on the server:
hg clone <old repo> <new repo> -r <revision>
to clone only up to the revision before the bad commit and deleted the
I tested it and it seems fine. I thought I ask better here to be sure, have I really made sure that there is no hidden history or hidden foot print lying around to expose the content of that bad commit?
Many Thanks,
Don't worry. After deleting <old repo>, it's definitely gone. Although a forensic expert might still find something interesting in the deleted blocks on disk.
Your clone command will work, but if your repository has multiple branches, that clone will not include them. So unless you carefully pull those in individually, you may have lost more than you intended. Likely this is not what you want...
The easiest way to remove a revision is using the strip command from the MQ extension. You can use this in combination with the rebase command (Rebase extension) to remove a changeset that already has children that you want to preserve; first rebase the children onto the parent, and then strip the offending changeset.
Do take care though that these are history modifying operations, so if the changeset is already shared with other users, it will still be in their repository. Even after they pull. They will need to repeat your steps to get rid of them, which is quite a pain in the ass. The change could even accidentally end up back in the main repository that way. (Note: this applies to your clone method as well.)
So if you need to do this, best to instruct all your users to make a fresh clone, or at least strip the change, and make a hook to prevent the changeset from being reintroduced. If you can’t contact and/or trust all your users (e.g. because it is open source), probably it is better to leave the changeset there and just change your production credentials. It’s already out in the wild anyway.
In the future there will be a better way to do remove or alter changesets with the “obsoletion” feature, slated for Mercurial 2.4. Once that is fully implemented, when users pull from your repository their repository’s history can automatically update accordingly. So keep an eye out for that feature.

A mercurial merge chose the wrong changes, what is the correct way to fix this?

Changes were made to our .vcproj to fix an issue on the build machine (changeset 1700). Later, a developer merged his changes (changes 1710 through 1715) into the trunk, but the mercurial auto-merge overwrote the changes from 1700. I assume this happened because he chose the wrong branch as the "parent" of the merge (see part 2 of the question).
1) What is the "correct" mercurial way to fix this issue, considering out of all the merged files, only one file was merged incorrectly, and
2) what should the developer have done differently in order to make sure this didn't occur? Are there ways we can enforce the "correct" way?
Edit: I probably wasn't clear enough on what happened. Developer A modified a line in our .vcproj file that removed an option for the compiler. His check-in became changeset 1700. Developer B, working from a previous parent (let's say changeset 1690), made some changes to completely different parts of the project, but he did touch the .vcproj file (just not anywhere near the changes made by Developer A). When Developer B merged his changes (becoming changes 1710 through 1715), the merge process overwrote the changes from 1700.
To fix this, I just re-modified the .vcproj file to include the change again, and checked it in. I just wanted to know why Mercurial thought that it shouldn't keep the changes in 1700, and whether or not there was an "official" way to fix this.
Edit the second: Developer B swears up and down that Mercurial merged the .vcproj file without prompting him for conflict resolution, but it is of course possible that he's just misremembering, in which case this whole exercise is academic.
I will address the 2nd part of you question first...
If there is a conflict, the automated merge tools should force the programmer to decide how the merge happens. But the general assumption is that a conflict will involve two edits to the same set of lines. If somehow a conflict arises because of edits to lines that are not close to each other the automated merge will blithely choose both of the edits and a bug will appear.
The general case of a merge tool always merging properly is very hard to solve, and really can't be with current technology. Here is an example of what I mean from C:
int i; // Someone replaces this with 'short i' in one changeset stating
// that a short is more efficient.
// ... lots of code;
// Someone else replaces all the 65000s with 100000s in another changeset,
// saying that more precision is needed.
for (i = 0; i < 65000; ++i) {
integral_approximation_piece(start + i/65000.0, end + (i + 1) / 65000.0);
}
No merge tool is going to catch this kind of conflict. The tool would have to actually compile the code to see that those two parts of the code have anything to do with eachother, and while that would likely be enough in this case, I can construct an example that would require the code to be run and the results examined to catch the conflict.
This means that what you really ought to do is rigorously test your code after a merge, just like you should after any other change. The vast majority of merges will result in obvious conflicts that a developer will have to resolve (even though that resolution is often fairly obvious), or will merge cleanly. But the very few merges that don't fit either category can't easily be handled in an automated fashion.
This can also be fixed by development practices that encourage locality. For example a coding standard that states "Variables should be declared near where they're used.".
I'm guessing that .vcproj files are particularly prone to this problem since they are not well understood by developers and so if conflicts do appear they will not be sure what to do with them. My guess is that this happened and your developer simply did a revert back to the revision (s)he checked in.
As for part 1...
What to do in this case depends a lot on your development process. You can either strip the merge changeset out and redo it, though that won't work very well if lots of people have already pulled it, and it will work especially poorly if there are lots of changesets that have already been checked in that are based on the merge changeset.
You can also check in a new change that fixes the problem with the merge.
Those are basically your two options.
The tone of your post seems to me to indicate that you may have some politics surrounding this issue in your organization, and people are blaming this error on the frequent merges of Mercurial. So I will point out that any change control system can have this problem. In the case of Subversion, for example, every time a developer does an update while they have outstanding changes in their working directory, they are doing a merge, and this kind of problem can arise with any merge.
In mercurial a merge doesn't have a single parent, it by definition has two and only two parents. When someone is merging they're making two choices:
What two changesets will constitute the two changes
Which of those changesets will be the left-parent and which will be the right-parent
Of those two questions the first is very important, and the second barely matters at all, though it took me a while to come to understand that.
You select the left-parent by using hg update X. That changes the output of hg parents (or in newer versions hg summary) and essentially determines what's in your working directory before the merge.
You select the right-parent by using hg merge Y. That says merge X (the working directory's parent) with changeset Y. As a special case, if there are only two heads in your repository and your parent is already one of them then Y will default to the the other.
I'd have to see your resulting graph to know just what the developer did, but it's possible he didn't update to one head or another before invoking merge, which would have him merging one head with some point back in history.
If your developer picked the right parents for the merge then the left vs. right doesn't much matter -- the only real difference is that when one uses hg diff or hg log -p or some other command that shows the patch for a merge changeset, it's displayed relative to the left-parent. That's, however, mostly a factor in display only. Functionally they're pretty much identical.
Assuming your developer picked the right changesets then what he should have done was test the result of the merge before committing it. Merging is software development, not an annoying VCS side effect, and not testing before committing is the error.
Fixing
To fix this, just re-do the merge correctly. Use hg update to set one parent, use hg merge to pick the other. Make sure your current working directory is correct and then commit. You can get rid of his bad merge using something like hg strip or better, just close down his branch with hg commit --close-branch after updating to it.
Avoiding
You say "mercurial auto-merge", but mercurial doesn't really auto-merge. It does a premerge which is an extremely cautious combination of obvious changes, but it's so careful it won't even merge for you if each merge parent adds code in the same region because it can't know which block of code you'd rather have first.
You can disable this premerge entirely or on a file-by-file basis using the merge tool configuration options:
https://www.mercurial-scm.org/wiki/MergeToolConfiguration?highlight=premerge