Mercurial: R with 'hg status', how to commit? - mercurial

If I do 'hg status' and see the following:
R flash/AC_OETags.js
it seems to mean that there is no file there, but there has been one at some point that has been removed.
How do I 'commit' this change so it stops showing up when I do 'hg status'?
==UPDATE==
The answer seems to be to commit the file. Actually, there are ~100 files with status R because I removed an entire directory tree. Anyone know how to commit all files in a directory tree in one go?
I don't want to do just hg commit, because there are other changes too.

The “R” means “Removed” so the next time we commit in Mercurial this file will be removed. (The history of the file will remain in the repository, so of course we can always get it back).
therefore run your hg commit command and all will be well
Thanks to hginit.com for that titbit - its my Mercurial bible

You can commit just that file:
hg commit flash/AC_OETags.js
however having "masses of other uncommitted files" is terrible process. You need to come up with a workflow that lets you commit frequently.

You can use the repository explorer from TortoiseHg to easily manage the files you want to include in a commit.
Also, removing a directory probably warrants a changeset in itself. You should get into the habit of committing more often (one concept, one commit... and it's local anyway). Furthermore, as long as you haven't pushed your changes to anyone (or anyone pulled from you) you could still use hg rebase --collapse to regroup some changesets if you think you have separated too much (this is a more advanced feature that I suggest you try on a test repository first as you could break things if you're not careful)

Related

Remove file from multiple (all) commits in a branch in Mercurial?

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.

How to re-commit last changeset with a different comment?

As I understand it, you can't really fix a comment in Hg. So what I would like to do instead is re-push the exact same changes (or at least "touch" the same files and commit & push again).
The reason this is necessary is because we have a bug tracking and build system that relies on specific comment patterns, and we need to make sure the right files get included in the build, but if I forget to update the bug # in my comment from my last commit, and I accidentally commit and push it under the wrong # because i'm overzealous, how can I re-push those same files again without manually going into each one and adding a space or line break just to create a diff?
To clarify, I can't "rollback" or something; it's already been pushed with the wrong message.
As far as I know, current Mercurial features provide no support for this. After the changeset has been pushed, there's little you can do to un-push it, besides stripping it from the server repo and any other developer's repo.
I guess you you should ask those who set up this workflow in your shop; they should've come up with some exception handlers for it.
We usually just ignore issues like this, and close the bug by hand, making sure the bug links to the correct changeset. If the changeset is really messed up (usually this means bad changes, not a malformed commit message), we resort to stripping.
Since your change has already been pushed you can't use a simple fix, like "hg commit --amend", but you can do something similar. Basically, the following commands re-do the commit with Mercurial's help:
CSET=...the changeset to re-do...
hg up -r "p1($CSET)" # Update the working directory to the parent revision
hg log -r "$CSET" -p > changes.patch
hg import --no-commit changes.patch
hg commit # And use the appropriate commit message.
Then, merge and push.
The only way that I could think of doing this is to commit two more changes, one would be an hg backout of the incorrect revision and the other would be an hg backout of that revision with the corrected comment.
I don't like that idea though and wouldn't recommend it if there was any way to fix the problem in your bug tracking system.

Mercurial: how to amend the last commit?

I'm looking for a counter-part of git commit --amend in Mercurial, i.e. a way to modify the commit which my working copy is linked to. I'm only interested in the last commit, not an arbitrary earlier commit.
The requirements for this amend-procedure are:
if possible, it should not require any extensions. It must not require non-default extensions, i.e. extensions which do not come with an official Mercurial installation.
if the commit to amend is one head of my current branch, no new head should be created. If the commit is not head, a new head may be created.
the procedure should be safe in a way that if for whatever reasons the amending fails, I want to have the same working copy and repository state restored as before the amending. With other words, if the amending itself can fail, there should be a fail-safe procedure to restore the working copy and repository state. I'm referring to "failures" which lie in the nature of the amend-procedure (like e.g. conflicts), not to file-system-related problems (like access restrictions, not being able to lock a file for writing, ...)
Update (1):
the procedure must be automatable, so it can be performed by a GUI client without any user interaction required.
Update (2):
files in the working directory must not be touched (there may be file system locks on certain modified files). This especially means, that a possible approach may at no point require a clean working directory.
With the release of Mercurial 2.2, you can use the --amend option with hg commit to update the last commit with the current working directory
From the command line reference:
The --amend flag can be used to amend the parent of the working directory with a new commit that contains the changes in the parent in addition to those currently reported by hg status, if there are any. The old commit is stored in a backup bundle in .hg/strip-backup (see hg help bundle and hg help unbundle on how to restore it).
Message, user and date are taken from the amended commit unless specified. When a message isn't specified on the command line, the editor will open with the message of the amended commit.
The great thing is that this mechanism is "safe", because it relies on the relatively new "Phases" feature to prevent updates that would change history that's already been made available outside of the local repository.
You have 3 options to edit commits in Mercurial:
hg strip --keep --rev -1 undo the last (1) commit(s), so you can do it again (see this answer for more information).
Using the MQ extension, which is shipped with Mercurial
Even if it isn't shipped with Mercurial, the Histedit extension is worth mentioning
You can also have a look on the Editing History page of the Mercurial wiki.
In short, editing history is really hard and discouraged. And if you've already pushed your changes, there's barely nothing you can do, except if you have total control of all the other clones.
I'm not really familiar with the git commit --amend command, but AFAIK, Histedit is what seems to be the closest approach, but sadly it isn't shipped with Mercurial. MQ is really complicated to use, but you can do nearly anything with it.
GUI equivalent for hg commit --amend:
This also works from TortoiseHG's GUI (I'm using v2.5):
Swich to the 'Commit' view or, in the workbench view, select the 'working directory' entry.
The 'Commit' button has an option named 'Amend current revision' (click the button's drop-down arrow to find it).
||
||
\/
Caveat emptor:
This extra option will only be enabled if the mercurial version is at least
2.2.0, and if the current revision is not public, is not a patch and has no
children. [...]
Clicking the button will call
'commit --amend' to 'amend' the revision.
More info about this on the THG dev channel
I'm tuning into what krtek has written. More specifically solution 1:
Assumptions:
you've committed one (!) changeset but have not pushed it yet
you want to modify this changeset (e.g. add, remove or change files and/or the commit message)
Solution:
use hg rollback to undo the last commit
commit again with the new changes in place
The rollback really undoes the last operation. Its way of working is quite simple: normal operations in HG will only append to files; this includes a commit. Mercurial keeps track of the file lengths of the last transaction and can therefore completely undo one step by truncating the files back to their old lengths.
Assuming that you have not yet propagated your changes, here is what you can do.
Add to your .hgrc:
[extensions]
mq =
In your repository:
hg qimport -r0:tip
hg qpop -a
Of course you need not start with revision zero or pop all patches, for the last just one pop (hg qpop) suffices (see below).
remove the last entry in the .hg/patches/series file, or the patches you do not like. Reordering is possible too.
hg qpush -a; hg qfinish -a
remove the .diff files (unapplied patches) still in .hg/patches (should be one in your case).
If you don't want to take back all of your patch, you can edit it by using hg qimport -r0:tip (or similar), then edit stuff and use hg qrefresh to merge the changes into the topmost patch on your stack. Read hg help qrefresh.
By editing .hg/patches/series, you can even remove several patches, or reorder some. If your last revision is 99, you may just use hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a.
Of course, this procedure is highly discouraged and risky. Make a backup of everything before you do this!
As a sidenote, I've done it zillions of times on private-only repositories.
Recent versions of Mercurial include the evolve extension which provides the hg amend command. This allows amending a commit without losing the pre-amend history in your version control.
hg amend [OPTION]... [FILE]...
aliases: refresh
combine a changeset with updates and replace it with a new one
Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.
See 'hg commit' for details about committing changes.
If you don't specify -m, the parent's message will be reused.
Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).
See https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolve for a complete description of the evolve extension.
Might not solve all the problems in the original question, but since this seems to be the de facto post on how mercurial can amend to previous commit, I'll add my 2 cents worth of information.
If you are like me, and only wish to modify the previous commit message (fix a typo etc) without adding any files, this will work
hg commit -X 'glob:**' --amend
Without any include or exclude patterns hg commit will by default include all files in working directory. Applying pattern -X 'glob:**' will exclude all possible files, allowing only to modify the commit message.
Functionally it is same as git commit --amend when there are no files in index/stage.
Another solution could be use the uncommit command to exclude specific file from current commit.
hg uncommit [file/directory]
This is very helpful when you want to keep current commit and deselect some files from commit (especially helpful for files/directories have been deleted).

How to retrieve an accidentally deleted patch in Mercurial with MQ

I had two patches in series, neither one applied, and I accidentally called qdelete on the wrong one. Is there any way to reverse this operation and get my patch back? I had a huge amount of work in this one!!!
The way to avoid this (and I know it's not helpful now, sorry) is to not just use Mercurial Queues, mq, but to use it with a patch repository. Mercurial/mq has great support for this.
When initially creating the queue you do:
hg qinit --create-repo
(instead of just hg qinit), which creates a new Mercurial repository in your .hg/patches directory. Then you can use:
hg commit --mq
to commit all your patch files, and bringing this back would be just a matter of:
hg revert --mq
The bottom line, and again I know it's not helping you now, but maybe it'll help the next guy or you later, is: if you're writing code and it isn't committed somewhere it doesn't exist -- commit and push early and often
Unfortunately, if you did not use the -k option when calling the qdelete command, the patch file also got deleted. Thus your only hope is either a backup or an tool that could perform some "undelete" operation.

Mercurial undo last commit

How can I undo my last accidentally commited (not pushed) change in Mercurial?
If possible, a way to do so with TortoiseHg would be prefered.
Update
In my concrete case I commited a changeset (not pushed). Then I pulled and updated from the server. With these new updates I decided, that my last commit is obsolete and I don't want to sync it. So it seems, that hg rollback is not exactly what I'm searching for, because it would rollback the pull instead of my commit.
One way would be hg rollback (deprecated as of Hg2.7, August 2013)
Please use hg commit --amend instead of rollback to correct mistakes in the last commit.
Roll back the last transaction in a repository.
When committing or merging, Mercurial adds the changeset entry last.
Mercurial keeps a transaction log of the name of each file touched and its length prior to the transaction. On abort, it truncates each file to its prior length. This simplicity is one benefit of making revlogs append-only. The transaction journal also allows an undo operation.
See TortoiseHg Recovery section:
This thread also details the difference between hg rollback and hg strip:
(written by Martin Geisler who also contributes on SO)
'hg rollback' will remove the last transaction. Transactions are a concept often found in databases. In Mercurial we start a transaction when certain operations are run, such as commit, push, pull...
When the operation finishes succesfully, the transaction is marked as complete. If an error occurs, the transaction is "rolled back" and the repository is left in the same state as before.
You can manually trigger a rollback with 'hg rollback'. This will undo the last transactional command. If a pull command brought 10 new changesets into the repository on different branches, then 'hg rollback' will remove them all.
Please note: there is no backup when you rollback a transaction!
'hg strip' will remove a changeset and all its descendants. The
changesets are saved as a bundle, which you can apply again if you
need them back.
ForeverWintr suggests in the comments (in 2016, 5 years later)
You can 'un-commit' files by first hg forgetting them, e.g.: hg forget filea; hg commit --amend, but that seems unintuitive.
hg strip --keep is probably a better solution for modern hg.
hg strip will completely remove a revision (and any descendants) from the repository.
To use strip you'll need to install MqExtension by adding the following lines to your .hgrc (or mercurial.ini):
[extensions]
mq =
In TortoiseHg the strip command is available in the workbench. Right click on a revision and choose 'Modify history' -> 'Strip'.
Since strip changes the the repository's history you should only use it on revisions which haven't been shared with anyone yet. If you are using mercurial 2.1+ you can uses phases to track this information. If a commit is still in the draft phase it hasn't been shared with other repositories so you can safely strip it. (Thanks to Zasurus for pointing this out).
Since you can't rollback you should merge that commit into the new head you got when you pulled. If you don't want any of the work you did in it you can easily do that using this tip.
So if you've pulled and updated to their head you can do this:
hg --config ui.merge=internal:local merge
keeps all the changes in the currently checked out revision, and none of the changes in the not-checked-out revision (the one you wrote that you no longer want).
This is a great way to do it because it keeps your history accurate and complete. If 2 years from now someone finds a bug in what you pulled down you can look in your (unused but saved) implementation of the same thing and go, "oh, I did it right". :)
hg rollback is what you want.
In TortoiseHg, the hg rollback is accomplished in the commit dialog. Open the commit dialog and select "Undo".
In the current version of TortoiseHg Workbench 4.4.1 (07.2018) you can use Repository - Rollback/undo...:
Its workaround.
If you not push to server, you will clone into new folder else washout(delete all files) from your repository folder and clone new.
I believe the more modern and simpler way to do this now is hg uncommit. Note this leaves behind an empty commit which can be useful if you want to reuse the commit message later. If you don't, use hg uncommit --no-keep to not leave the empty commit.
hg uncommit [OPTION]... [FILE]...
uncommit part or all of a local changeset
This command undoes the effect of a local commit, returning the affected
files to their uncommitted state. This means that files modified or
deleted in the changeset will be left unchanged, and so will remain
modified in the working directory.
If no files are specified, the commit will be left empty, unless --no-keep
Sorry, I am not sure what the equivalent is TortoiseHg.
after you have pulled and updated your workspace do a thg and right click on the change set you want to get rid of and then click modify history -> strip, it will remove the change set and you will point to default tip.
I ran into this issue recently, although my situation was slightly different - I had already pushed the commit I wanted to undo. I solved my problem with hg backout <revision-code>. It seems to work in a similar way to git revert. From this answer:
backout: create a new commit that is the inverse of a given commit.
Net effect is an undo, but the change remains in your history.
In TortiseHg this can be done by right clicking the commit you wish to undo and selecting Backout.... TortiseHg doc here.
I think there's an argument for creating a new undo commit instead of removing the previous commit outright. From this article about git revert:
Instead of removing the commit from the project history, it figures
out how to invert the changes introduced by the commit and appends a
new commit with the resulting inverse content. This prevents Git from
losing history, which is important for the integrity of your revision
history and for reliable collaboration.