I just ran:
hg add .*
which matched all ../something files and which was something I certainly did't want! What is the easiest way to undo this command?
Not exactly what I was after, but made my life easier:
hg forget "set:added()"
this unmarks all the files that were added in the working repository. Obviously I also unmarked all the files that were added in preceding commands, so as I said this is not exactly what I was after...
If you've got a lot of uncommitted adds that you don't want to have to do over, you can use a mercurial fileset that only picks out pending adds in subdirectories of the parent directory (use this in the same directory where the erroneous command was issued):
hg forget "set:../** and added()"
Mercurial doesn't remember what path you used to refer to a file, so this will forget all files (under the parent directory) that were just added; but if you were deep in a large repository, it'll limit the scope of what you discard.
Your question is similar to this recent question, but here we have an extra condition on the mistakenly added filenames.
There is not built-in way to undo a hg add command.
The underlying problem is that hg add is manipulating the so-called "dirstate" (short for "working directory state". This is where pending changes such as files scheduled for commit is stored — and this storage is unversioned.
There is an extension, though, that can help you: hg-multiundo will make backups of all files touched by Mercurial, including the dirstate. This means that you can use it to undo things like hg add or even hg revert --no-backup.
Related
I have seen Remove file from a commit in Mercurial - but I have very little experience with Mercurial, so I'd like to ask and make sure if this is doable, and how.
There is a software that is developed in Mercurial, and I wanted to try and add a feature. So when I cloned the repo, first I did was added my own branch, and started hacking there. Already in first or second commit of this branch, I added multiple files hg add test1.bmp, hg add test2.bmp and so on, and committed.
Then I kept on hacking other files (haven't touched these test1.bmp, test2.bmp etc since), and made about 3 or 4 commits after the commit where the bmps are added. Nothing has been pushed anywhere - my local copy of the Mercurial repo and my branch in it is the only place where these files are referenced. And just now I realize I shouldn't have added those files at all.
Is it possible to remove these files from all of the commits where they feature, since the first commit where they were added?
Or maybe I should formulate the question in singular - is it possible to remove a file from all of the commits where it features, since the first commit where it was added? (if it is possible for one file, then I can just repeat the process for any additional file I'd like to remove)
Yes this is possible.
However, this is a more advanced use of mercurial and will require you enabling at lease one extension.
As a new user, my recommendations would be to simply use mercurial basic management and remove the file(s) of concern:
hg remove <file>
You can then commit the change.
While this will not remove the file(s) from all changesets, it will remove it
going forward. This honestly is the recommended way of managing working content.
It should be noted that this is likely your only option if you have pushed changes to the parent repository. If you have pushed your changes to the parent repository, you will also have to edit it which makes things much more complicated and the potential for a serious mistake more likely.
If you truly want to remove it from previous changesets, you will need enable the histedit extension (included with mercurial).
[extensions]
histedit =
Since you are a relatively new user to mercurial, I strongly recommend that you backup your repository and experiment there before attempting this on you working copy.
The process I recommend for this is as follows:
Note: this only works as described for changesets that have not been pushed and have phase = draft (or secret)
1) Identify all changes where file(s) are added or modified
You will need to know each changeset where the file(s) where modified or added. You will need to modify each of these changesets in the reverse order that they where added.
You can use:
hg log file
to list changesets where the file was modified or added.
2) Slowly edit each affected changeset (working your way backwards)
Use the histedit to display all show all changesets that can be modified/edited in your default editor.
hg histedit
Find the first changeset you identified and change it from pick to edit and save the change.
This will drop you into histedit edit mode. This is the state just before the changeset was committed. This means you can make changes such as modifying, unedifying. Adding or removing content. In this case we want to undo any changes to the file(s) in question.
hg revert file
or
hg remove file (if this is the changeset where the file as added)
3) recommit changeset
Once you have reversed the file changes/additions, you need to inform histedit
that you are done.
hg histedit --continue
This will cause the changeset to be recommitted with the modifications you made including editing the commit message.
Repeat this for each changeset until completed.
Note: While you can select multiple changes to edit in histedit, I recommend doing one at a time to help reduce complexity. Remember to do the in the reverse order that they where committed to help reduce / eliminate any merge conflicts.
Again a recommend practicing on a repository copy until you have the process firmly understood. Since you are modifying repository history, this can have potential negative effects of a mistake is made.
I highly recommend reading this: https://book.mercurial-scm.org/read/changing-history.html.
I accidentally renamed a file outside of Mercurial. When I committed the change, Mercurial treated the change as two unrelated files (ie. a remove and a add). I need to go back to diff the two revisions but I don't know how to do so when Mercurial sees them as two respective files across different revisions. What can I do to diff the files?
You didn't say what operating system you were using. The following will work with bash on Linux:
diff <(hg cat -r rev1 file1) <(hg cat -r rev2 file2)
You can replace diff with another program like vimdiff if you want a visual diff.
If you want to actually fix the history so that Mercurial is aware of the rename (and can use that information in future merges if needed), there's a way to do so documented on the Tips and Tricks page on the Mercurial wiki.
Current contents copied here for ease of use (and in case the link gets broken later):
Steps:
Update your working directory to before you did the rename
Do an actual "hg rename" which will create a new head
Merge that new head into the revision where you did the "manual" rename (not the head revision!)
Then finally merge the head revision into this merge result.
Advice:
Make a clone first and work on that, just in case!
After finishing the steps, use a file compare tool to check that the original and the clone are identical
Check the file history of any moved file to make sure it is now restored
That being said, if all you want to do is compare the contents at the point in time, you can definitely accomplish that without making Mercurial aware of the rename (as mentioned in Stephen Rasku's answer). In fact, you can use a combination of "hg cat" and an external comparison tool to compare any files, not just ones that Mercurial knows about.
Fix history:
Update to first changeset with new-filename, save file outside WC
Update to parent of bad replacement changeset, replace file correctly (with rename tracking), commit, got second head
Rebase all changesets from old anonymous branch on top of fresh good changeset
--close-branch on bad-replacement changeset or delete this unwanted changeset or leave inactive head intact
Just made the mistake of using addremove to try and remove some files that were deleted without using hg remove
Now have hundreds of files that are going to be added on the next commit
Is there anyway I can quickly remove all these added files without having to resort to a bash script or even worse hg removing or forgetting each file manually?
If you want to just use internal hgcommands, you can do the following:
hg forget "set:added()"
Which will forget any file that's marked as "added" in the working directory. It makes use of the rather powerful filesets feature of Mercurial.
There are additional filters you can use when specifying files, which allows you to easily fix other mistakes. For example, easily re-add removed files but nothing else hg add "set:removed()". The functionality is similar to (tho' thankfully simpler than) mercurial revsets, and can be studied with:
hg help filesets
You do it quite easily on the command line using something along the lines of :
hg status --added --no-status | xargs hg forget
This should forget all files added since the last commit.
May I suggest to add the files you never want to add to a .hgignore file so this won't happen again ?
I'm using Mercurial to read and debug a complex project, and my modify of the project can be divided into different group of files clearly. For example, if I modified four files
src1.cc src1.hh src2.cc src2.hh
It's apparent that I can divide them into two file groups such as group src1 includes src1.cc src1.hh and group src2 includes src2.cc src2.hh.
I'm wondering if I can revert a group of files by a simple command like 'hg revert group-name-alias' instead of listing all the filename of the group, which is a awful idea if I have modified many files?
Any help really appreciated!
From what I can understand of your use-case, you can:
Use patterns in the hg revert command. This means that you can
run hg revert src1* to revert all the first group.
Most probably, though, your stuff is in sub-folders and thankfully
you can specify a parent folder to the revert command.
So say your files are really like: foo/src1.cc, foo/src1.hh,
bar/src2.cc, bar/src2.hh. In that case, you can revert all the
second group with hg revert bar, assuming you're in the top folder.
If you're already in the bar folder, you can run hg revert ..
You can specify several patterns.
Use Mercurial queues if each one of your "file groups" is also
a different unit of work (a different bug fix or feature). This is not
so desirable if all files belong to the same unit of work, though.
No. To the best of my knowledge, Mercurial has no mechanism for grouping files.
You could do some trickery with aliases ([alias] revert-group-name = revert src2.cc src2.hh in ~/.hgrc), but aliases can only be prefixes, and can't perform variable expansions.
If your files are simple enough, you could use shell globbing (hg revert src2*), or a shell variable (GROUP_NAME="src2.cc src2.hh", then hg revert $GROUP_NAME).
You could also consider writing a small Mercurial extension. If you know Python, they don't take very long (my first took me about 30 minutes).
If the filenames meet patterns, you can use that pattern:
hg revert src1*
or
hg revert src1*.*
If those files are in a specific directory, you can do this:
hg revert dir\*
If the directory is more than one level deep and you want to get that directory and all its subdirectories, you can use this version of that commend:
hg revert dir\**\*
I am new to Mercurial. Just cannot find the right command. Tried update/checkout with no luck. I am using local repository. Thanks
I think you want hg revert -r<rev> <file> (this will change that file to be as it was at the given revision).
As djc said revert alters a file in place to match a prior revision. If you want it not in place you can use hg cat -r revisionid filename (substituting revisionid and filename of course) which will output the file to stdout, suitable for redirecting anyplace you'd like.
hg revert does indeed solve this problem. But I think that you are confused about a broader range of things than simply the answer to your question and want to try to answer more fully.
hg update is a whole repository command and will not work on individual files. It is unlike the subversion svn update in this way. If you do hg --help update you can see that this is the case because the command takes no file argument. It can be used to move your whole repository to a particular snapshot, but cannot be used to do that to just one file.
If you type hg --help you see a list of commands. It's a rather large and somewhat daunting list, but if you read through it, you'll find this line:
revert restore individual files or directories to an earlier state
Now, if you just want the last state for comparison purposes, there is another command you may be interested in, and that's hg cat. That will allow you to print out the contents of a file at any particular revision. You can then redirect its output into some other file. Then you can have the previous known good version of your file and the old version to compare side-by-side.
The reason why Mercurial has a separate update command is that it is possible to do something in Mercurial that is impossible in Subversion. You can update to an earlier version, make changes, then commit. This will create a branch. The update command has the effect of also changing the parent revision of the current working directory as well as changing the contents of all the files in that directory to that parent revision's versions.
That means revert changes the contents of a file (or even the whole repository if you give the command the right arguments) but leaves the parent revision of the current working copy the same.
You can find out the parent revision (or revisions in the case of a merge) of the current working copy by using the hg parents command.
In Subversion revisions are a strictly linear progression. Mercurial creates branches at the drop of a hat, and they are almost as easy to merge. Revisions form a DAG, not a strictly linear progression.
To extract a specific revision of a specific file you can do this on Windows:
hg cat "<FileToBeExtractedPath>" -r 9 > "<ExtractionPath>"
Here, 9 is the revision number.
Or even better:
hg cat "<FileToBeExtractedPath>" -r 9 -o "<ExtractionPath>"
Came here trying to get the previous version, so here is the exact command:
hg revert -r .~1 <file>