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)
Related
We are using mercurial in a single repository. We have a master branch and a develop branch (as well as feature branches, but they aren't germane to the issue at hand).
We tag the master branch with releases (5.1.0.102, etc). We do our development on develop.
But now we want to fix a bug in a previous version. There are a lot of questions here on SO about this issue, but none of them seem to explain what I want to do.
What I want to do is this:
Update to the point where we released (say 6.1.1)
Fix a number of bugs in that release
Label that resulting code state as (6.1.2)
Do a build of this new 6.1.2 codebase.
Migrate those fixes into the develop branch
Do this in such a way that I can go back to 6.1.2 and fix bugs there if need be.
I can't seem to do this via updating. I tried to update to the 6.1.1, create a branch, and go from there, but that brings in the tip of the master branch, including all subsequent changes.
Is there a standard way of doing this? Did I explain that correctly so you guys get what I need to do? It seems like this is a pretty common thing to do.
You don't need to explicitly create a branch. The way I would do it is this:
Update to the point where you released (6.1.1 in the master branch).
Make changes and commit them.
Tag the latest commit in master as 6.1.2.
Pull those changes into the develop branch.
Continue working.
If you need to make more changes, then simply repeat the above but using the 6.1.2 tag in the master branch.
You really shouldn't need to create a named branch unless you truly want to have a full-out branch. What you probably want to do is:
update to 6.1.1
make the edits
commit (will create a new un-named branch)
tag that new revision as 6.1.2.
You can then merge that edit into your develop branch
As long as you are updating to a revision earlier than the tip on the Master branch, the commit will make a new branch off of it.
This will leave the version tagged so you can easily get back to it.
My question is essentially the same as here but applies to mercurial. I have a set of files that are under version control, and one save operation changes quite a lot of files. Some of the resulting changes are important for revision control, and some of the changes are just junk. I can "partition" off the junk into separate files. These junk files need to be part of a basic checkout in order for it to work, but their contents (and changes over time) aren't that important for revision control. Right now I just tell all our developers not to commit these files, but we all forget and it creates a lot of extra baggage in the repository. I don't really like the svn solution proposed because there are quite a lot of files and I want a simple clone to just work without all this extra manual work, so I was wondering if mercurial has a better alternative. It's kind of like hg shelve but not quite, and kind of like ignore, but not quite. Is there some hg extension that allows for this? Can git do it?
Mercurial doesn't support this. The correct way to do it is to commit thefile.sample and then have your developers (or better you deploy script) do a copy from thefile.sample to thefile if thefile doesn't exist. That way anyone can update the example file, but there's no risk of them committing their local changes (say their personal database connect string).
Aha! So TortoiseHG's repository and global settings have an Auto Exclude List where you can define a list of files that will be unchecked by default when the status, commit, and shelve dialogs open. So they still show up, but the user has to check them in order to actually do a commit. The setting is stored in hgrc, but it's under the [tortoisehg] heading so it's not supported by mercurial per se. Nevertheless, it fits my needs.
One solution to this is to use nested tree support (submodule in git), where the "junk" would be put in a different repository (to avoid cluttering the main repo), while enabling checking out the whole thing out in a consistent manner (right version of both repos in sync).
https://www.mercurial-scm.org/wiki/Subrepository?action=show&redirect=subrepos
In git, submodules are one solution to this issue - but they are not that great UI-wise. What I do instead is to keep two completely independent repositories, and using the subtree merge strategy when I need to update the main repo with the junk repo: http://progit.org/book/ch6-7.html
The qrefresh command in the MQ extension don't make sense to me. I'll explain my assumption:
If you don't know on which revision should a certain patch be applied, it have a very little value. You just can't theoretically know what does the rejects mean. And even if there are no rejects on a certain revision, you're not sure the whole revision would compile.
Once you qrefresh a certain patch in your patch queue, you're actually losing the parent of the next patch in the queue. So that without your intervention this next patch is/might be useless.
In order to fix the next patch, you'd better merge it instead of hand-editing the .rej, files. Not just because of the better tools, if you have the original un-qrefresh'ed patch, you have more information, the qrefresh caused you to lose information you actually need in order to make the change you made to the patch meaningful.
Therefor I don't understand why one would ever want to use this command.
A better alternative is, to apply all the patches, then hg update to the parent of the patch you want to change, then, hg revert the working directory to the patch you want to change. Change this patch, commit it to a new revision, and then rebase all the other patches on this new revision.
I simply don't understand when qrefresh is relevant when you're not editing a single patch only. It seems that git's approach (apply the patch to a local branch) makes much more sense than a patch queue.
Am I correct, and I'd better of use rebase? Is there something I missed?
migrated from kiln.se.com due to no response and low view rate
EDIT: after writing the answer below, I stumbled upon the chapter
about patches of Mercurial The
Definitive Guide. It says more or
less the same but is much more
detailed that my answer. It also
suggest a way (a bit convoluted for my
taste, but anyway) to use 3-way merge
with patches as the OP was looking
for.
Maybe you see mq only as a patch import tool ? That is not my primary use, and for me qrefresh is very useful. The typical use case for me is when I'm working over the top of published repository.
I usually work with a series of patches I'm writing at the same time. I begin by creating a new empty patch. When I believe some (part of a) feature is finished, I qrefresh the top patch to make it include all changes made from patch creation time (or last qrefresh). Then I create a new empty patch and continue writing code that belong to the next patch.
If at a later time when working on another patch I see some change that should be made inside a previous patch (because it logically belongs to it), I do not make the change in the top patch nor create a new patch. First I qrefresh the current patch, then qpop to the previous patch where the changes belong, then make my changes. When it's done I qrefresh again the old patch, then qpush back to where I was working, and so on.
When you work this way, merges are usually very easy and I get nearly no rejects qpoping and qpushing around.
When I belive my full patch series is ready to be published, I qfinish the whole series, and start again with a new empty patch stack.
It is possible to do the same kind of things with rebase, but then you would need feature like git interactive rebase.
The whole point about working with patches is that patches are not yet commited, so can easily be changed, and for that you need qrefresh. Well, I could achieve the same result creating new patches and qfolding them, but there would really be not point doing that, just two commands instead of one.
Now, when patches are external contributions, as a main maintener to my project contributions are included from patches provided by contributors and they never get directly to the repository. They first get inside my main patch stack. If they make changes to the same parts of program I'm working on they are likely to cause rejects (and if so I basicaly do not insert it at all, it is likely to wreak havoc). If they apply to some other part of the program not being currently changed, they basically merge without any problem an can be imported at any point in the patch stack, no obligation to insert them upon a specific revision. But I always read the changes, and quite often I slightly change the contributed code. Then again I use qrefresh to update the external patch to what I belive it should be.
You should pick kriss's answer, s/he explains it all very well, but here's a paper about the software that inspired the patch management feature in both mercurial and git, quilt:
http://www.suse.de/~agruen/quilt.pdf
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
...so I've gotten used to the simple stuff with Mercurial (add, commit, diff) and found out about the .hgignore file (yay!) and have gotten the hang of creating and switching between branches (branch, update -C).
I have two major questions though:
If I'm in branch "Branch1" and I want to pull in some but not all of the changes from branch "Branch2", how would I do that? Particularly if all the changes are in one subdirectory. (I guess I could just clone the whole repository, then use a directory-merge tool like Beyond Compare to pick&choose my edits. Seems like there ought to be a way to just isolate the changes in one file or one directory, though.)
Switching between branches with update -C seems so easy, I'm wondering why I would bother using clone. I can only think of a few reasons (see below) -- are there some other reasons I'm missing?
a. if I need to act on two versions/branches at once (e.g. do a performance-metric diff)
b. for a backup (clone the repository to a network drive in a physically different location)
c. to do the pick&choose merge like I've mentioned above.
I use clone for:
Short-lived local branches
Cloning to different development machines and servers
The former use is pretty rare for me - mainly when I'm trying an idea I might want to totally abandon. If I want to merge, I'll want to merge ALL the changes. This sort of branching is mainly for tracking different developers' branches so they don't disturb each other. Just to clarify this last point:
I keep working on my changes and pull my fellow devs changes and they pull mine.
When it's convenient for me I'll merge ALL of the changes from one (or all) of these branches into mine.
For feature branches, or longer lived branches, I use named branches which are more comfortably shared between repositories without merging. It also "feels" better when you want to selectively merge.
Basically I look at it this way:
Named branches are for developing different branches or versions of the app
Clones are for managing different contributions to the same version of the app.
That's my take, though really it's a matter of policy.
For question 1, you need to be a little clearer about what you mean by "changes". Which of these do you mean:
"I want to pull some, but not all, of the changesets in a different branch into this one."
"I want to pull the latest version of some, but not all, of the files in a different branch into this one."
If you mean item 1, you should look into the Transplant extension, specifically the idea of cherrypicking a couple of changesets.
If you mean item 2, you would do the following:
Update to the branch you want to pull the changes into.
Use hg revert -r <branch you want to merge> --include <files to update> to change the contents of those files to the way they are on the other branch.
Use hg commit to commit those changes to the branch as a new changeset.
As for question 2, I never use repository clones for branching myself, so I don't know. I use named branches or anonymous branches (sometimes with bookmarks).
I have another option for you to look into: mercurial queues.
The idea is, to have a stack of patches (no commits, "real" patches) ontop of your current working directory. Then, you can add or remove the applied patches, add one, remove it, add another other one, etc. One single patch or a subset of them ends up to be a new "feature" as you probably want to do with branches. After that, you can apply the patch as usual (since it is a change). Branches are probably more useful if you work with somebody else... ?