Undo an accidental hg strip? - mercurial

I have accidentally run hg strip, and deleted a stack of commits. I have not done anything in the repo since. Is there a way for me to bring back this stack of commits, to undo the hg strip I just ran?

As long as you didn't run the strip with the --no-backup option, the stripped changesets can be found in the repository under .hg\strip-backup. If you sort the directory content by date the latest one is likely the one you need to restore. Restore it with hg unbundle <filename>.

It is possible to hg pull from a strip backup file as an alternative to using hg unbundle.
As noted in a comment on another answer to this question, hg unbundle has fewer options and only works with bundles, but can unbundle more than one bundle at a time. Whereas hg pull can pull from a single source (share/web/bundle) and has other options.
Here's an example of using hg pull based on an external post by Isaac Jurado:
Usually the backup is placed in REPO/.hg/strip-backup/. See the
example below:
$ hg glog
# changeset: 2:d9f98bd00d5b tip
| three
o changeset: 1:e1634a4bde50
| two
o changeset: 0:eb14457d75fa
one
$ hg strip 1
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
saved backup bundle to
/Users/hchapman/ttt/.hg/strip-backup/e1634a4bde50-backup.hg
And then, what one would do to recover those changesets would be:
$ hg pull $(hg root)/.hg/strip-backup/e1634a4bde50-backup.hg

Here is a worked example of unbundle from an external post. I've cleaned it up slightly to make it a little more general:
Recovering stripped files when using Mercurial
If you accidentally strip a patch and do not have a backup for it, you
can still recover your files using Mercurial. To recover your files:
Open a Microsoft Windows Command Prompt window.
Navigate to the project folder where you stripped the files.
Run the dir command
Navigate to the .hg folder where Mercurial stores all relevant project
files.
Run the dir command again.
Navigate to the strip-backup folder where Mercurial stores the backup
bundles of stripped patches.
Run the dir command again. Multiple files display in the directory
that use the <hash>-hg format. They are the backup bundles of stripped
patches.
Use Windows Explorer to find the required file. Open the strip-backup
folder in Windows Explorer, and sort by Date modified descending.
Unless the necessary backup bundle is already known, [it is recommended to]
restore the bundles in reverse chronological order starting
from the most recent bundle.
Navigate back to the project folder.
To restore a bundle, run hg unbundle .hg\strip-backup\<bundle_file_name>. ... You may want to add it to the
PATH environment variable to make it accessible globally.
Synchronize the project [using hg pull] to see the restored patch. If
the restored patch is not the one needed, then continue restoring the
patches in reverse chronological order until the required patch is
retrieved.
Note: You may restore the backup bundles in any order, instead of
using reverse chronological order. However, it may not be safe to do
so. You may end up attempting to restore a backup bundle, which has a
dependency on another backup bundle that has not been restored. In
this case, you will get an error.

Related

Mercurial: how to revert changes purging files except those ignored (covered by '.hgignore')?

I made some exploratory changes to my code in a project under mercurial version control, so afterwards I wanted to discard all changes and go back to the last version in the remote repo.
hg pull
hg update -r default -C
hg --config "extensions.purge=" purge --all
What I didn't realize is that this will delete any untracked file, including those ignored. In particular eclipse directories like .settings. Obviously I don't want to delete those.
I know I can use patterns with the purge command, and most of the time I will want to use it only with changes under the source code directory, but if I had made changes not only under src, but also config, added a file at project directory level and whatnot, is there any way that purge could automatically pull files and directories from the .hgignore file to be excluded so I don't have to think all that directories and files in which I have untracked files?
Well... you explicitly used a flag which means "delete everything, even if ignored". From hg help purge:
--all purge ignored files too
So it should work, if you skip the '--all' parameter to purge.

Why don't mercurial file sets work when adding files?

I'm trying to use mercurial file sets to add all the files in a directory tree, excluding very large files and any binary files. Cribbing from the mercurial documentation, this command should do it:
hg init
hg add 'set: size("<1M") and not binary()'
However this returns a status code of 0, and hasn't added anything to my new, empty repo. I've tried just 'set: not binary()' and that didn't work either.
The frustrating thing is that although I can google for mercurial file sets, and find lots of examples, I can't find anything to help troubleshoot when it doesn't work!
I don't have a .hgignore file, and it's a fresh empty repo. Mercurial 4.2.2.
The directory where I'm testing this has a couple of artificially created files for the purpose of testing. In my real use case, I inherit a multi-gigbyte tarball of assorted sources and binaries from a client, and I want to get all the sources into mercurial before I start hacking to fix their problems, hence the need to exclude the binaries and large files that otherwise choke mercurial.
Here's my little test script:
#!/bin/sh -ex
dd if=/dev/urandom of=binary_1k bs=1 count=1024
dd if=/dev/urandom of=binary_2M bs=1 count=2097152
echo "This. Is, a SMALL text file." > text_small
hexdump binary_1k > text_1k
hexdump binary_2M > text_2M
ls -lh
file binary_1k
file binary_2M
file text_1k
file text_2M
hg init
hg add 'set: size("<1M") and not binary()'
hg status -a
hg add 'set: not binary()'
hg status -a
hg add 'set: size("<1M")'
hg status -a
At the end of this, each status command reports no files in the repo, and the add commands report no errors.
The problem is that file sets do a query of Mercurial's repository data base, which knows only about files that are part of the repository or have been added.
One solution is to add all, and then to get rid of the files that you don't like, e.g.:
hg forget 'set:size(">1M") or binary()'
This works, because the query also requires recently added files, even if they haven't been committed yet.

Mercurial diff/patch by example

I have read only permission to an hg repo and am trying to develop and test changes to it locally. The problem is that I am in the middle of changing dev machines and am caught in a weird/akward state across the two machines.
On my old machine I made lots of changes to the repo, locslly. I just cloned the repo on my new machine, but obviously that doesn't contain the changes from my old machine. I need a way to createe a patch/diff from my local working copy on my old machine, and then apply them to my local working copy on my new machine. The problem is that I already commited (hg commit -m "Blah") the changes on my old machine to the distributed repo on it.
What set of specific commands can I use to create a patch/diff of my old machine and then apply it to the repo on my new one?
Update
I commited all changes on my old machine and then ran hg serve, exposing http://mymachine.example.com:8000.
On my new machine, where I had made some different changes (locally) than the changes from my old machine, I ran hg pull http://mymachine.example.com:8000 and got:
myuser#mymachine:~/sandbox/eclipse/workspace/myapp$ hg pull http://mymachine.example.com:8000
pulling from http://mymachine.example.com:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 16 changes to 10 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
So I run hg merge:
myuser#mymachine:~/sandbox/eclipse/workspace/myapp$ hg merge
abort: uncommitted changes
(use 'hg status' to list changes)
What do I do now?!?
You can use:
$ hg diff > changes.patch
To create a patch file, then:
$ patch -p1 < changes.patch
To apply that patch file on your new machine.
Well, that's actually fantastic, mercurial is a distributed version control system and you do not need to go via any patch file at all: simply pull the changes from your old machine to your new machine:
hg pull URL
where URL can be any network URL or also ssh-login, e.g.
hg pull ssh://mylogin#old.maschine.box or hg pull path/to/old/repository/on/nfs/mount
`
Alternatively you can also use bundle and unbundle. They create bundles which can be imported in the new mercurial easily and keep all meta-information.
hg bundle -r XXX --base YYY > FILENAME
where YYY is a revision you know you have in your new repository. You import it into your new repo with hg unbundle FILENAME. Of course you can bundle several changesets at once by repeating the -r argument or giving a changeset range like -r X:Y.
The least comfortable method is a via diff or export:
hg export -r XXX > FILENAME or equivalent hg diff -c XXX > FILENAME where you need to import the result with patch -p1 < FILENAME or hg import FILENAME.
The easiest way is to do this is to ensure that all work on your old machine is committed. Then use this command on it from the base of your repo:
hg serve
which creates a simple http server on this repo. The monitor should state the name of the http URL it is serving.
On your new machine, just pull from that URL.
Once you've pulled your old changes you can stop the hg serve process with ^C.
The advantages of this method are that it is very quick, and that it works on just about any system. The ssh method is also quick, but it won't work unless your system is configured to use ssh.
Answer to Update
The OPs update is asking an orthogonal question about how to merge changes pulled from a server with local changes. If you haven't already done so, try to digest the information in this merge doc and this one.
Merging is for merging changesets. The error is happening because you have local changes that haven't been committed which mercurial can't merge. So the first thing to do is to commit your local changes, then you will be able to merge.
But before you merge, I strongly recommend that you are merging what you think you are merging. Either ensure there are only 2 heads, or specify which head you are merging with. When merging, you have to be at one of the heads you wish to merge; it's usually better to be at the head with the most changes since the common ancestor because the diffs are simpler.
After you've merged, don't forget to commit the merge. :-)

How to restore from a mercurial backup

I created a backup of my mercurial repository using
hg bundle --all name.hg
Now, how would i restore my repository using the backup file? Say if my whole repository is corrupted and all i have is just this *.hg file., Is it possible to restore my repository(assuming that is what backup is supposed to be for., but did i miss any step while backing up the repository ?)
Could someone please help me with this.
Thanks in advance
To quote the help page:
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.
So you would be creating a new empty repository and pull from your backup file.
hg unbundle [-u] FILE...
apply one or more changegroup files
Apply one or more compressed changegroup files generated by the
bundle command.
options:
-u --update update to new tip if changesets were unbundled
Note that you can also use regular file system tools to backup your repository. Bundles are useful when you need to transfer a set of changes somewhere else (or when disk space for the backup is an issue, because they are compressed and smaller than the on-disk repo itself).
Another possibility is simply using hg clone:
hg clone name.hg name/

File in repository after clone, but no history

We have a Mercurial repository converted from Subversion a while ago and have today noticed that there are files in the repository that have no history whatsoever.
One of the sympomts of this behaviour is that hg status reports the file as clean, while hg log reports no changesets for the same file:
> hg clone [repo]
> hg st -c FileWithMissingHistory.cs
C FileWithMissingHistory.cs
> hg blame FileWithMissingHistory.cs
FileWithMissingHistory.cs: no such file in rev [...]
> hg log FileWithMissingHistory.cs
> hg log FileWithMissingHistory.cs -f
abort: cannot follow nonexistent file: "FileWithMissingHistory.cs"
> hg log -v | grep FileWithMissingHistory.cs
[gives output, there arechangesets mentioning the file]
Obviously the filenames have been changed in the example. I've tried using hg verify, but this command reports that the repo is fine. Has anyone experienced this and is there anything we could do to bring the history "back to life"? Placing dummy history on the files in question would be acceptable, but suboptimal.
EDIT:
I've done some more investigation and noticed that "FileWithMissingHistory.cs" was renamed from another filename (hg copy + delete) in revision 238. If I do hg update -r238 and hg log on the file at this revision I do not get any history. Doing hg log on the original file reports the history as expected, so it seems that the history is somehow lost during copy (again, the file is renamed using hg copy, and the changeset clearly indicates that the file has been copied).
Sounds strange, actually impossible. What I would try to debug this issue is to update to different revisions and check at which revision the file appears in the working copy the first time. If you do this in a binary search fashion (similar to how the bisect extension works), you should find a revision which introduces the file after a few updates.
This does not solve the problem, but it may help in tracking down its source.
I've finally tracked down the cause of the effects mentioned above and it seems that this is caused by mixed casing issues. Some of the files are located in directories with lowercase names while others are located in the directories with equal names, only that the case is mixed (e.g. "directory/FileWithHistory.cs" and "DiReCtOrY/FileWithMissingHistory.cs"). On Windows, both files will be located in the same directory causing issues.