We're hitting a problem when merging in Mercurial where whitespace changes are causing merge conflicts which mask any "real" conflicts we may have and makes merging a nightmare. We've recently conformed to a formatting style which changed the indentation of files in some branches and merging has become almost impossible since.
As an example, try:
hg init testrepo
cd testrepo/
echo "This is text." > newfile.txt
hg add newfile.txt
hg commit -m "Created a file."
hg branch newbranch
echo "This is some more text." > newfile.txt
hg commit -m "Changed text in the file."
hg update default
echo " This is text." > newfile.txt
hg commit -m "Added indentation whitespace."
This results in two branches, one with whitespace changes, the other with textual changes:
# 2 " This is text".
|
|
| o 1 "This is some more text."
|/
|
o 0 "This is text."
When trying an hg merge on this I get a merge conflict. If we have conflicts on every line it becomes difficult and time consuming to sort out the "real" conflicts. What I'd prefer is for the merge process to think "OK, changeset 2 line 1 differs from the parent only in whitespace so consider it unchanged. Pick changeset 1 line 1 as the merged result."
Ignoring whitespace or not is a choice your merge tool makes. You can configure all manner of merge tools for use with mercurial as shown here: MergeToolConfiguration
Mercurial's internal pre-merge won't/can't ignore whitespace, but if your external merge tool does and it finds only whitespace changes it will exit immediately, and if it finds other that whitespace changes it can hide the whitespace changes when it does load.
For example, with the popular kdiff3 merge tool you'd enable the "White space 2/3-file merge" setting and tell it whether to pick left or right.
Tl;Dr: turn this on in your merge tool, not in mercurial.
Is this a situation where scrubbing the whitespace would be difficult? If not, I would write a simple script that scrubs all whitespace before checkin to avoid this. The downside is that you would lose formatting, but most IDE's can easily restore that for you.
The alternative would be to use a standard formatter before checking in to do the opposite... add white space where it should be.
Related
I find myself doing the following a lot:
C:\Code>hg pull
pulling from http://server/FogBugz/kiln/Repo/Project/Rebuild/trunk
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 4 changes to 4 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
C:\Code>hg merge
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, dont forget to commit)
C:\Code>hg commit -m "Merged"
C:\Code>hg push
pushing to http://server/FogBugz/kiln/Repo/Project/Rebuild/trunk
searching for changes
remote: kiln: successfully pushed 2 changesets
My question is, what is a better/more useful commit message to use after merging a pull from the repository. Are there any best practices that people use in distributed version control systems for this sort of thing?
If you use the fetch extension it automates the pull,merge step into one step, fetch. The message it auto-generates is something along the lines of "automatic merge". The hg developers seem to think this is reasonable as the extension is now distributed with the base.
Merge messages don't seem to be contain a particularly high amount of information. Your message seems reasonable.
[[ offtopic, we sometimes use them as an opportunity for a pun on the word merge]]
There is no one way so here is what I have tried to adhere to.
On commit messages:
Jus remember that those messages are the only strings that would connect you to some one who is try to decipher the reasons for the commit.
Key is to provide a description that is going to be a useful commentary on code development.
So when some one uses hg log , he has a nice commentary on how the software is being developed.
Some good practices:
Link it with your bug management system:
fixes #3456, new feature #2435 etc
or a more descriptive one of what changes it is bringing in the repo
Give credits
In fact, what I do mostly is. Look at
the current state of "hg log" and see
what useful message would mean a
logical progression in understanding the latest commit.
As long as "merg" is in the message somehow, we've had fun using the opportunity to fill our mercurial logs with hilarity. For example, we've used merge messages such as "real-estate mergage loans are at an all time low" or "a Merge Griffin television production."
You can collect all the newly added changesets' commit messages into a file by
$ hg log --rev 'reverse(p2():ancestor(p1(),p2())-ancestor(p1(),p2()))' \
--template '{desc}\n' \
> commit-message.txt
then manually edit commit-message.txt, and finally use it as the log message:
$ hg commit -l commit-message.txt
You could use the rebase extension, so hg pull --rebase would rebase your repo to the central repo's tip. This negates the need for merging after a pull.
I added an alias for it:
[alias]
pure = pull -u --rebase
Works well for us.
More details are at the RebaseProject page.
For mundane merges, where you're only working with one repository, I think just "merge" is fine. Usually you don't even know everything that got merged in because it's all other people's changes anyway.
The one time I would suggest being more verbose would be when you're working with more than one repository. If you have a devel repo and a stable repo, and you're pulling bug fixes in from stable, I would just mention that in the merge: "merging with stable". Those merges tend to be bigger, so it helps explain them to people who come along later.
Is there a simple way to check if a merge/rebase will yield file conflicts, without actually performing the merge/rebase?
I want to be able to decide whether to:
rebase if the touched file set (mine vs. theirs) are different
merge if we've been messing with the same files.
Since a bad merge (caused by resolving conflicts the wrong way by human error) is easier to detect and reverse if I do a merge of two heads, rather than having done rebase. Especially if I push my changes and than later realized that something was messed up.
(It's not possible to always check everything beforehand, as we don't have a totally comprehensive test-suite.).
And.. I'm running Windows. :)
So, with some aid from Martin's answer, I've come up with the rebaseif extension, which does what I want.
Essentially, it tries to rebase using the internal merge tool, if that fails (which it does for any conflict), it aborts and does a merge with the user's preferred tool.
See https://bitbucket.org/marcusl/ml-hgext/src/tip/rebaseif.py for details.
Update
In recent months, I've gone back to just do a merge, since it's inherently safe. A non-conflict rebase might still muck things up since dependent files can affect the change. (i.e. a rebase loses information of how the code looked before merge).
As the rebaseif author, I recommend to use plain old merge instead. :)
There is no reason to use hg merge if the changes overlap and hg rebase otherwise since hg rebase make a merge internally and will let you resolve it using the same tools as hg merge.
As for testing if a merge or rebase will cause conflicts, then you can use
$ hg merge --tool internal:merge
in Mercurial 1.7 to override your normal merge tool configuration. (The --tool internal:merge part is new, use --config ui.merge=internal:merge in earlier versions of Mercurial.)
Following the merge,
$ hg resolve --list
will tell you the results and you will get back to where you started with
$ hg update --clean .
You can see if two changesets, REV1 and REV2, affect any of the same files doing something like:
(hg status --change REV1 --no-status ; hg status --change REV2 --no-status) | sort | uniq --repeated
If that has any output then the same file is touched in both revisions.
That could easily be made a shell script like:
#!/bin/sh
(hg status --change $1 --no-status ; hg status --change $2 --no-status) | sort | uniq --repeated
which could be run as any of these:
./find_overlaps c8f7e56536ab d9e2268e20b9
./find_overlaps 1 33
If you really wanted to get fancy you could tweak the script to automatically run merge or rebase depending on whether or not any lines were found.
If you're on windows my god help you. :)
I tried to merge two heads in Mercurial. After merging, I didn't commit and did some more changes. Then I tried to commit and got the following message:
abort: cannot partially commit a merge (do not specify files or patterns)
I'm using TortoiseHG as visual shell, and Beyond Compare for comparing and merging. And I'm relatively new to all of them.
What should I do to finish commit successfully?
Mercurial/TortoiseHg is correct in telling you that you should not partially commit a merge. Partial means that you do not commit all files at once.
The underlying reason for this message is that is gives you the wrong results. When you merge two changesets in Mercurial, you are creating a new changeset with two parent changesets. This merge changeset shows others how you want everybody else to combine the two changesets.
Let us imagine that you start with changesets A and B and want to merge them. This creates a graph like this:
... --- [A]
\
[M]
/
... --- [B]
Pretend that we added the line A! to a.txt in the A changeset and that we added B! to b.txt in the B changeset. Just two independent changes that does not conflict. If Mercurial allowed you to do a partial commit, then you could do this:
hg merge
hg commit -m 'Added A!' a.txt # creates M
hg commit -m 'Added B!' b.txt # creates M'
and the result is this graph:
... --- [A]
\
[M] --- [M']
/
... --- [B]
If you look at b.txt along the path B, M, M', then you will see that the line with B! was introduced in B, removed in M and reintroduced in M'!
This is not what you want from a merge changeset: a partial merge throws away changes from one branch just to introduce them again in a followup commit. Mercurial trusts you when you create M: it really believes that M contains the correct mix of A and B. In particular, if the B! line is removed in M, then it will remain gone when you merge M with other changesets.
So Mercurial is trying to protect you from creating a bad history by not allowing partial merges.
I think you have aliases in hgrc file. Try to remove [alias] section and commit again.
What should I do to finish commit
successfully?
One of the benefits of Mercurial (or git or any other DVCS) is that you can perform a commit at any point in your development process and it will be both fast and private. It will be fast because you should be committing to a local copy of the repository residing on your hard drive, and it will be private because no-one will see your change set until you push them to the server (or other master repository).
Therefore, to partially answer your question, the appropriate thing to do would have been to commit the merge without your addition changes, and then apply and commit your next wave of changes. If you are using TortoiseHG to peform the merge it will actually prompt you to commit the merge before leaving the GUI because this is the intended HG workflow.
That being said, I made some changes on a named branch (ie: new head), merged it back into the default branch, exited the TortoiseHG GUI without committing, made some more changes, and then committed with no problem. I will ask some clarifying questions below your original inquiry.
I had this problem because I had deleted some files. I reverted the files to restore them, then was able to commit. I then deleted the files and did a second commit.
I had the same problem and I was NOT specifying any files and using command-line.
The problem was the [default] section in my .hgrc
[defaults]
commit = -X project/web.config
So it added specific files to every commit-operation by default.
Review your defaults section for potential problems.
I had the same problem and the command I gave was
hg commit -m Merge with 1234
I figured it out after sometime that the commit message "Merge with 1234" has to be given in quotes as the command takes "with" and "1234" as file name params.
please check it in your case.
I'm new to collaborating with Mercurial. My situation:
Another programmer changed rev 1 of a file to replace 4-space indents with 2-space indent. (I.e. changed every line.) Call that rev 2, pushed to the remote repo.
I've committed substantive changes rev 1 with various code changes in my local workspace. Call that rev 3.
I've hg pulled and hg merged without a clear idea of what was going on.
The conflicts are myriad and not really substantive.
So I really wish I'd changed my local repo to 2-space indents before merging; then the merge will be trivial (i'm supposing). But I can't seem to back up. I think I need to hg update -r 3 but it says abort: outstanding uncommitted merges.
How can I undo the merge, changes spacing in my local repo, and remerge?
BTW: if you just revert the merge you did and 3 is not your revision number you can do this:
hg update -C -r .
You can discard uncommitted changes with the -C (or --clean) flag:
hg update -C -r 3
BEWARE: Everything that was not committed will be gone!
After that you should probably use some kind of code formatter tool to do the entire operation, or at least some find and replace with regular expressions. Something as simple as replacing what matches ^____ (use 4 spaces instead of underscores) with __ (2 spaces), repeated a few times (unless you have insanely some nested code) should work.
To undo an uncommitted merge, use
hg update --clean
which will check out a clean copy of the original merge parent, losing all changes.
I apparently just needed to hg update -C -r 3, which overwrites my local files with the rev in mind (which is what I thought hg update would do; but I was wrong.) Thanks for my help!
Say, I made many changes to my code and only need to commit a few of those changes. Is there a way to do it in mercurial? I know that darcs has a feature like this one.
I know hg transplant can do this between branches, but I need something like this for committing code in the present branch and not when adding change sets from some other branch.
If you are using TortoiseHg 1.x for Windows, this feature is implemented beautifully right out of the box (no extensions required).
Run the TortoiseHg Commit Tool.
Choose a file for which you only
want to commit a subset of its
changes.
Click on the Hunk
Selection tab in the preview pane.
Double-click or use the spacebar to
toggle which change hunks should be
included in the commit.
For TortoiseHg 2.x, the Hunk Selection tab is now gone. In its place, is the Shelve tool. It has a few more features than the old hunk selection. Those new features come at the cost of some added complexity.
Note that there is no need to explicitly enable the Mercurial Shelve extension when using this feature. According to Steve Borho (lead TortoiseHg developer) in response to a different TortoiseHg question: "We have a local copy of the shelve extension and call into it directly."
For TortoiseHg 2.7+, this functionality has been improved and re-introduced. It is now built directly into the Commit tool:
Notice in the file list on the left that the top file is checked to indicate it will be included, the second file is unchecked because it will not be included, and the third file, Sample.txt, is filled (the Null checkbox indicator) because only select changes from that file will be included in the commit.
The change to Sample.txt that will be included is checked in the lower-right change selection portion of the image. The change that will be excluded is unchecked and the diff view is grayed out. Also notice that the icon for the shelve tool is still readily available.
MQ as Chad mentioned are one way. There's also more lightweight solutions:
Record extension which works roughly the same way as darcs record. It's distributed with mercurial.
Shelve extension which allows you to "shelve" certain changes, allowing you to commit only a subset of your changes (the ones that are not shelved)
I feel like I'm missing something because nobody has suggested this already.
The normal "hg commit" command can be used to selectively choose what to commit (you don't have to commit all pending changes in the local working directory).
If you have a set of changes like so:
M ext-web/docroot/WEB-INF/liferay-display.xml
M ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
M ext-web/docroot/WEB-INF/portlet-ext.xml
You can commit just two of those changes with...
hg commit -m "partial commit of working dir changes" ext-web/docroot/WEB-INF/liferay-display.xml ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
Not super convenient from the command line because you have to hand-type the files to selectively commit (vs a GUI check-box process like tortoise) but it's about as straightforward as it gets and requires no extensions. And file-globbing can probably help reduce typing (as it would above, both committed files uniquely share "liferay" in their pathnames.
The Mercurial Queues tutorial is terrible for this use case. All the examples I have seen assume you have yet to make a commit and you are refreshing a single patch. Most of the time this is not the case, and you have 2 or 3 commits that you want to squash together or change in some other way.
Lets say you have this sort of history:
---O---O---A---B---C
The first example is to squash commits A, B, and C. First init mq:
$ hg qinit
Now we need to "import" the commits A, B and C into the patch queue. Lets assume they are the last 3 commits. We can use the "-N" revision syntax to import them like so:
$ hg qimport -r -3:-1
That means import as patches from 3 patches back up to the last commit. You can check the status of these patches with hg qseries. It should show something like this:
$ hg qseries
101.diff
102.diff
103.diff
Where the numbers 101, 102 and 103 correspond to the local revision numbers of the commits A, B and C. Now these patches are applied, which means the changes that they describe are already in the working copy. You can get rid of the changes the working copy and remove them from the history of commits, saving them in patch form only, by using hg qpop. You can either say hg qpop; hg qpop to pop changes C and B off the stack, or specify a patch to "pop to". In this case, it would be something like this:
$ hg qpop 101.diff
now at: 101.diff
You now have the patches for commits B and C in the patch queue, but they are not applied (their changes have been "lost" - they only exist in the patch queue area). Now you can fold these patches into the last one, i.e. we create a new commit that is the equivalent of the sum of the changes A+B+C.
$ hg qfold -e 102.diff 103.diff
This will show your editor so you can change the commit message. By default the message will be the concatenation of the commit messages for the changes A, B and C, separated by asterisks. The nice thing here is that hg qfold will tab-complete the patches if you are using bash and have the hg-completion script sourced. This leaves the history like this, where A+B+C is a single commit that is the combination of the 3 patches that interest us:
---O---O---A+B+C
Another use case is if we have the same sort of history as before, but we want to drop patch B and merge A+C. This is pretty similar to above actually. When you get to the qfold step, you would simply fold in the last commit rather than the last 2 commits:
$ hg qfold -e 103.diff
This leaves the change for B in the patch queue, but it is not applied to the working copy and its commit is not in the history. You can see this by running:
$ hg qunapplied
102.diff
The history now looks like this, where A+C is a single commit that combines changes A and C:
---O---O---A+C
A final use case might be that you need to apply only commit C. You'd do this by running the qimport as above, and you would pop off all patches you didn't want:
$ hg qpop -a
The -a flag means pop off all patches. Now you can apply just the one you do want:
$ hg qpush 103.diff
This leaves you with this history:
---O---O---C
Once you are done with all this, you need to finish off the queue fiddling. This can be done with:
$ hg qfinish -a
So there we are. You can now run hg push and only commit exactly what you want, or hg email a coherent patch to the mailing list.
Some time has passed. Seems the best option now is hg commit --interactive
You can use the record extension, which is distributed with Mercurial.
You need to enable it in your ~/.hgrc file first, by adding it to the [extensions] section:
[extensions]
record=
Then, just type hg record instead of hg commit, and you will be able to select which changes to which files you want to commit.
You can also use the crecord extension which provides a nicer interface to review and select the changes. (It is not distributed with Mercurial, though, and I've seen it occasionally mess up a commit so it's not completely bug-free.)
I believe Mercurial Queues fills this role for Mercurial. There's a pretty good tutorial linked there.
Try qct (Qt Commit Tool). It has a "select changes" feature that starts up a 3-way merge tool for you to undo individual changes. After you commit, those changes you "undid" come back.
I use commit-patch. It's a script that lets you edit the diff before committing. It's really nice with Emacs's diff-mode and vc-mode.
In the past I used crecord, but it has bugs related to unicode (actually the record extension has the bugs, which crecord depends on).
First you must forget everything you ever knew about GUI's and return to the commandline. Next from the commandline do this:
hg stat > filelist.txt
This pipes all your modified files into a text file called filelist.txt
Next edit your filelist to include only the files you wish to commit.
Finally commit using the fileset sytnax:
hg commit "set: 'listfile:test.txt'"