Use of Mercurial hg bundle and hg export vs merging? - mercurial

When exactly would you use hg export and hg bundle?
These commands are listed on the Mercurial quick start guide but we're not clear when to use them.
Currently we manage dev by having different repositiories and merging between them. Ie:
cd myapp-1.01
hg pull ../myapp-1.0
hg merge
hg commit
hg push
When would you use export and bundle instead of the approach we use?

The primary difference is whether or not the parent changeset exists in the destination repository. If for example your source repo has this:
[A]--[B]---[C]
and your destination has this:
[A]--[B]
and you want to send [C] you could use bundle (or just push/pull).
If, however, your destination repository had:
[A]--[D]
and you wanted to add [C] to it you'd have to use export and import.
In brief: bundle is for when you want to do push/pull but don't have a good network path, and export is for when you want to send the logical contents of a changeset rather than that specific, exact changeset.

Bundle is better fit to save a specified range of changesets into a file for easy transfer (such as, sending them by email to be applied to a different repository somewhere else).
From hg --help bundle:
The bundle file can then be
transferred using conventional means
and applied to another repository with
the unbundle or pull command. This is
useful
when direct push and pull are not available or when exporting an entire
repository is undesirable.
Export seems to generate a list of headers+diffs for some range of changesets, but the helpfile doesn't mention if this helps automate transferring them somewhere else.
Moreover the file output argument for export is formattable according to revision number etc, which leads me to believe that the command would be commonly used to save revisions in a way that makes it easier for you to look at them (as files).

Related

Restore history to split repository

Rightly or wrongly (almost certainly wrongly) I've ended up in the following position:
We used to have one big mercurial repository. We have now moved a large portion of this code base in to a separate repository. Looking back, it seems we could have done this in such a way that kept the file history, but naively we simply copied the files in to the new repository.
We are now in a position where the two repositories have been split, but I want to attach the file history of the moved files to those in the new repository. The files have been deleted in the original repository - but this history obviously still exists.
Is there anyway to "pre-pend" the history of the files in the original repository to those in the split repository?
The convert extension allows you to convert a Mercurial repository to another one while excluding and modifying filenames (using the --filemap option).
So use the convert command twice, one for each split, and use a corresponding filemap which only involves the files supposed to be in the particular target repository.
If you already did commits in the split repos you do not want to loose, use the convert approach anyway and afterwards migrate your new commits made in the splits w/o history to your new split repos made with convert:
Suppose your old splits with lost history are os1 and os2 and your new splits made with the convert command are ns1 and ns2. Then in ns1 you would do
hg pull --force os1 (force is required because you pull from an unrelated repo),
hg rebase -s <first-new-commit-made-in-os1> -d <last-converted-commit-in-ns1> (rebase new commits onto your split made with convert)
hg strip <first-commit-at-all-in-os1> (discard everything you pulled from os1 but not needed anymore)
Do it similarly with os2 and ns2
I don't know about attaching the file history after you've already done the split, but if you can do it all over again this is one option:
In your original repository, go back to the last revision (REV) before you deleted the files:
hg up -r REV
Go up one level from the original repository and make two new clones:
hg clone OriginalRepo Split1
hg clone OriginalRepo Split2
Go into Split1, delete the files you don't want in that repository, and commit. Do the same for Split2. These two are now your new split repositories, both with a complete history. Of course, the history for all deleted files (even those you initially didn't want in the repository) will exist equally in both repositories as well.
If you've done a lot of work in your new repositories after you made the split, you might be able to add these to your Split1 and Split2 by using export/import (check hg help import and hg help export). Depending on the number of changes you've made, there might be better ways to do this (e.g. mercurial queues), but this is what came to my mind first.

Use .diff in tortoise mercurial tool

I use Tortoise Mercurial tool to manage my mercurial repository.
And I have a separate .diff file containin0g changes to a file in my repository.
Is there any way how to use that diff to update my file ?
thank you
Most Linux repositories comes with the patch program. You can then execute:
patch original.data difference.diff
Patch will modify the original.data file in such a way that if one would calculate the diff between the final and original state, one gets the same difference.diff again.
.diff files are in general not visible in a subversioning respository. They are stored internally to hide the several commits from the user. Diffs however can be usefull to analyze the difference between two commits. Say for instance somebody worked on your project and made a lot of commits, you might want to inspect what that person actually did without having to read the reports of all commits (since some changes can be undone in the next commit)

What is the right way to avoid shamap corruption when converting mercurial repositories?

I'm trying to build a pruned Mercurial repository from a larger one and need to pull in changes from several branches. I want to use hg convert, but I am getting errors like
abort: unknown revision '81b79760e1350d185dbf645ab67633eda9d52ada'!
when try to use convert to get changes from a related branch. Here's what I did. I started with mybranch and used
hg convert --filemap filemap mybranch mybranch_converted
Then, to capture any changes to the paired down converted repository from anotherbranch (that shares a common ancestor with mybranch), I invoked
hg convert --filemap filemap anotherbranch mybranch_converted
but that fails with an abort error like the one I showed above.
I am lead to understand that this indicates that the shamap file created by the first conversion is borked somehow, so what should I do to generate a good shamap file? I'd also be interested in knowing what could cause this process to fail considering that it is so straight forward. Also, as this may be relevant, I should note that the ancestor of mybranch and anotherbranch was itself generated by converting yet another Mercurial repository.
I think that message is telling you that one of the changesets you're pulling in has a parent whose node id doesn't show up in the destination repo -- and it doesn't show up because your initial convert changed the nodeids.
Rather than doing two converts, you should do two pulls and a single convert like this:
hg init both_unconverted
hg -R both_unconverted pull ../mybranch
hg -R both_unconverted pull ../anotherbranch
hg convert --filemap myfilemap both_unconverted both_converted
That way you're not trying to graft the new branch onto already modified changesets.
It's possible you could get your route to work with a --splicemap, but I'm not certain and the suggestion above does the same thing more simply.

Mercurial Remove History

Is there a way in mercurial to remove old changesets from a database? I have a repository that is 60GB and that makes it pretty painful to do a clone. I would like to trim off everything before a certain date and put the huge database away to collect dust.
There is no simple / recommended way of doing this directly to an existing repository.
You can however "convert" your mercurial repo to a new mercurial repo and choose a revision from where to include the history onwards via the convert.hg.startrev option
hg convert --config convert.hg.startrev=1234 <source-repository> <new-repository-name>
The new repo will contain everything from the original repo minus the history previous to the starting revision.
Caveat: The new repo will have completely new changeset IDs, i.e. it is in no way related to the original repo. After creating the new repo every developer has to clone the new repo and delete their clones from the original repo.
I used this to cleanup old repos used internally within our company - combined with the --filemap option to remove unwanted files too.
You can do it, but in doing so you invalidate all the clones out there, so it's generally not wise to do unless you're working entirely alone.
Every changeset in mercurial is uniquely identified by a hashcode, which is a combination of (among other things) the source code changes, metadata, and the hashes of its one or two parents. Those parents need to exist in the repo all the way back to the start of the project. (Not having that restriction would be having shallow-clones, which aren't available (yet)).
If you're okay with changing the hashes of the newer changesets (which again breaks all the clones out there in the wild) you can do so with the commands;
hg export -o 'changeset-%r.patch' 400:tip # changesets 400 through the end for example
cd /elsewhere
hg init newrepo
cd newrepo
hg import /path/to/the/patches/*.patch
You'll probably have to do a little work to handle merge changesets, but that's the general idea.
One could also do it using hg convert with type hg as both the source and the destination types, and using a splicemap, but that's probably more involved yet.
The larger question is, how do you type up 60GB of source code, or were you adding generated files against all advice. :)

How can I do a changeset based merge instead of file-by-file based merge with Mercurial?

When performing a merge with Mercurial, it wants to merge conflicting files one at a time which just isn't a productive workflow on large merge sets. Instead, what I would like to do is merge the entire changesets of both heads (like using kdiff3 to diff 2 heads). To me that sounds straightforward but I can't figure out how to achieve it.
So far, the closest I can get is to go through the merge the usual way, leave all the conflicts unresolved (a file at a time...), and then hg vdiff -rHead1 -rHead2 - but vdiff (using kdiff3) doesn't seem to have options for passing the tool an output dir (the current working dir) and instead launches with the output dir as a tempdir (possibly -o is the answer?).
Let me put it another way - I want to use kdiff to merge two heads into my working directory. I want the results in my working dir to be my merge that I can commit.
I must be missing something obvious, I can't be the only one who wants to do this.
I came up with a solution that achieves what I want but I still feel like it's a kludge.
Start with an empty working dir with 2 heads: Mine and Theirs.
Update working dir to Mine:
hg update [My head's rev here]
Perform a merge, but fail all files that Merc can't handle automatically without launching a merge tool and keep "My" files when in conflict:
hg --config "ui.merge=internal:fail" merge
See https://www.mercurial-scm.org/wiki/TipsAndTricks#head-9f405488b6d3b3d092a09aafa28db515ba44c742 for how-to merge/fail details.
Now I've got a working dir with as much as auto could figure out, but any outstanding files still untouched from Mine. (Use hg resolve -l to see the Mercurial's resolution status of current files)
Now I can vdiff my working dir against the Theirs head which gives me the high level, changeset-to-changeset merge that I was looking for.
hg vdiff -r [Theirs head's rev here]
Note: If you're using WinMerge for your vdiffs , then make sure it has an /r switch as an option which will do a subdirectory compare and - if WinMerge config is set to use Tree-View - will give a great tree comparison. From Mercurial.ini:
[extdiff]
cmd.vdiff = C:\Program Files\WinMerge\WinMergeU.exe
opts.vdiff = /e /ub /r /dl other /dr local
Now I can work the entire directory which includes the unresolved files and make project wide changes as necessary (ie. maybe resolving one file requires additional changes in another).
When done use resolve to mark all files resolved for Merc and then commit.
hg resolve -m
Whew! Here's hoping this helps someone else!
I relayed the question to #mercurial on irc.freenode.net a couple of days ago. mpm (the author of Mercurial) gave sort of an answer (it was only half an answer, so I didn't immediately pass it on here). He said that one might be able to do something where you let Mercurial merge the files automatically (and insert the <<<< and >>>> merge markers where there are conflicts).
Then use a merge tool that knows about these markers: this will let you resolve them all at once instead of doing it on a file by file basis. A starting point would be the page on merge tool configuration. It explains that
[ui]
merge = internal:merge
will make Mercurial inserte the merge markers. Here I tested it by making two files x.txt and y.txt which I then modified with conflicting changes in two clones. The merge simply gave:
% hg merge
merging x.txt
warning: conflicts during merge.
merging x.txt failed!
merging y.txt
warning: conflicts during merge.
merging y.txt failed!
0 files updated, 0 files merged, 0 files removed, 2 files unresolved
use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
All files were processed in one go, I did not have to confirm anything per file like you describe.
The files now contain merge markers like this:
% cat x.txt
foo
<<<<<<< local
hehe
=======
foobar
>>>>>>> other
The next step is to find a tool that can take a directory tree with such files and let you resolve them. I looked at kdiff3, but did not figure out how to use it to operate on a single file alone, it seems very focused on comparing pairs of files/directories.
I'm not sure how much this half answer helps you -- maybe you also got stuck at this point? But I hope it can help others who want to have the merge markers inserted into all files and then resolve the conflicts by hand.
I think this answers your question.
sounds like you want the extdiff command:
i have these in my ~/.hgrc (I prefer meld, but you can change it to kdiff3, etc)
[extensions]
hgext.extdiff =
[extdiff]
# add new command called meld, runs meld (no need to name twice)
cmd.meld =
With extdiff your merges occur in your working directory, and moreover you can pass any extra parameters to your diff program with -o:
$ hg help extdiff
hg extdiff [OPT]... [FILE]...
use external program to diff
repository (or selected files)
Show differences between revisions for the specified files, using
an external program. The default program used is diff, with
default options "-Npru".
To select a different program, use the -p option. The program
will be passed the names of two directories to compare. To pass
additional options to the program, use the -o option. These will
be passed before the names of the directories to compare.
When two revision arguments are given, then changes are
shown between those revisions. If only one revision is
specified then that revision is compared to the working
directory, and, when no revisions are specified, the
working directory files are compared to its parent.
options:
-p --program comparison program to run
-o --option pass option to comparison program
-r --rev revision
-I --include include names matching the given patterns
-X --exclude exclude names matching the given patterns
Try setting ui.merge. See this page for more details.