How to keep local changes in Mercurial and make it "invisible" - mercurial

In my local repo, I have a file A and I made some changes. But I didn't want to submit this changes to remote repo. The question is if I didn't submit this changes in TortoiseHG, everytime I changed other files, A will be listed in the "changelist window".
I know, TortoiseHG has a shelve function. It can store temp files. But files in shelve will revert to origin status.

Commit the change and then modify the phase of the commit to "secret". Note that any child changesets of a secret changeset will also be secret.
hg help phases
You might want to maintain a private branch with these changes - just make the first commit to the branch secret and then periodically merge from the main branch to your private branch.
An alternative is to do the above but without making the changesets secret. This will allow pushing the branch to a central server which gets the benefits of backups, etc and also the possibility that these changes might be useful to other developers (but still not on the main branch).

Consider using Mercurial patch queues to manage local changes. With MQ you can queue up local changes and stash them out of the way for future use.
For the extension's documentation, here's the standard workflow you'd use for putting away local changes for future use:
$ hg qnew choosename
$ hg qpop
$ # ...
$ # restore
$ hg qpush
$ hg strip -k choosename
$ hg qremove choosename
There's also shelve, but I've never used it.

Related

Remember uncommitted changes

I have some uncommitted changes C in my repo. I would like remember that changes in any way and get clean code (without that changes), make a little change and commit it. Now, I would like to recover my changes C and continue working on it. I know that I can deal with it using a lot of ways, but that ways are irritating. How to do it using mercurial?
So, to be more precise I need something like a stack:
Working on the code. Remember changes C on the stack.
hg update --clean
Make a change C2. Commit it.
Pop from stack a changeset C and work on it. But, now the repositorium contains committed change C2 and uncommitted C. It may cause that I need to merge but I expect that this merge will be invisible from the point of view repositorium.
While you certainly can work with mercurial queues, there's IMHO an easier and nicer way: change your default phase to secret and work with those commits like normal commits. Commits in phase secret are mutable and will not be exposed by push and pull commands acting on the repo.
This process has the advantage that you do not need to change your workflow - whether you work with commits you want to share (phase draft or public), or whether you still consider them work-in-progress and keep them locally only.
Additionally if you enable the evolve extension, you gain several benefits: it becomes even easier to amend commits and evolve (thus rebase) all child commits which depend on it.
The big advantage over the use of the mercurial queues is that you can make full use of the inbuild merge features - thus if the underlaying code changes, rebasing the new changesets is WAY easier and natural than using queues and hg shelve.
See the introduction to hg phases and changeset evolution which needs the evolve extension.
Enable the Mercurial Queues extension in your mercurial.ini or .hgrc file:
[extensions]
mq =
Then you can,
hg qnew save # save work in progress as a temporary commit
hg qpop # remove that commit
Make some more changes....
hg ci -m "new changes"
hg qpush # push the saved commit back.
hg qfinish -a # convert all temp commits to full commits.
You can also enable the shelve extension:
[extensions]
shelve =
Then you can:
hg shelve # "put away" current uncommitted changes.
*do other work*
hg unshelve # bring the shelved changes back
See hg help mq and hg help shelve for more info.
I've tried shelve, mq as described in other answers but to be honest I generally stick with:
hg diff > saved.patch # This assumes you've not aliased diff to a UI!!!
hg update -C
.. work
hg patch -f --no-commit saved.patch # I alias this for less typing
.. continue
Less book-keeping involved, its never gone wrong unlike shelve, and the patch itself is more easily portable. Just use common-sense and either make sure the patch applies fully, or use the --partial option and manually complete the patch.

Pushing and pulling with hgsubversion without manual shelve step

I'm using TortoiseHg with an SVN repository using the hgsubversion extension.
I like to use hg pull --rebase when I pull, to mirror what SVN does on svn update. Because I'm using hgsubversion, I will need to rebase anyway before I push, so I may as well do it in one step.
Additionally, hg push will automatically do a rebase internally, there is no way around that.
My difficulty is that hg rebase will refuse to work if I have any uncommitted changes. So to push or pull from SVN I always need to hg shelve first and then remember to do hg unshelve after. This can get really annoying and I always forget.
Ideally I'd like to tell TortoiseHg to do this for me automatically, but I'd settle for a command-line alias. I tried putting an alias like svnpull = !hg shelve && hg pull --rebase && hg unshelve in my config as suggested here but I get an error "user: abort: response expected" instead of being asked for my password. What can I do to avoid manually shelve/unshelve steps every time I interact with the central repository?
I can't actually commit my changes locally and just avoid pushing the local change, because hgsubversion doesn't respect the secret phase and hgsubversion doesn't support designating a revision to push. So unfortunately none of the answers to this similar question will work for me. And anyway I'd need manual steps to arrange for my "local only" changeset to always be on the tip.
The solution was to use repository hooks. I added this to my .hg/hgrc config file:
[hooks]
pre-pull = hg shelve
post-pull = hg unshelve
pre-push = hg shelve
post-push = hg unshelve
Don't enter password manually, automate it with keyring (questionable on Windows) or using [auth] section of in project's .hgrc
Sample from my local hg-repo for remote SVN-backend
[auth]
assembla.prefix = https://subversion.assembla.com
assembla.username = USER
assembla.password = PASSWORD
and entering password not needed anymore
Another idea: you haven't push immediatelly your WIP, yes? You have only to have it on top of "other" work, true? You can in this case commit, rebase, and continue to work with the same tip, modifying it with commit --amend

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. :-)

Safe way to purge history - Mercurial

I cloned a project to my local directory and made a lot of changes. My current goal is to push my changed code to a new branch in the remote repository. And eventually this new branch will be merged back to default.
My problem is, because of some stupid effort in the past a few weeks to try to recover some missing files, I end up with a few branch names that I don't want being shown in public.
Here's what I have:
$hg branches
dev-v02 197:xxxxx
dev2 194:xxxxx
dev 183:xxxxx
qa 189:xxxxx
$hg branch
dev-v02
My question is, if I push my current branch dev-v02 to the remote repository by "hg push --new-branch", and this branch later get merged back to default, will the unwanted branches show up in history of default? And if so, is there a safe way to purge them?
I do NOT want to discard my changes. I just don't want the unwanted branches showing up in "hg branches" or "hg his" commands by whoever later clones the project from the remote repository. I searched online and found "hg strip" but I couldn't tell from the article if it would also remove the changes I've made. Thanks.
Edit: I just cloned my local repository by "hg clone -r 197 original-dir dest-dir" as suggested by both kevin and chessbot and now hg branches shows:
dev-02 192:xxxxx
qa 187:xxxxx (inactive)
I guess "qa" remains because I had pushed it to the remote as a QA branch and closed it later, and I just have to live with that. I will push from this new directory from now on. Thanks guys for your help.
Try hg push --new-branch -b dev-v02 to specify that you're pushing only that branch.
(See: https://www.mercurial-scm.org/repo/hg/help/push)
Another thing you could do: Clone the repository locally on your machine, strip out the branches you don't want, and then push that clone to the server. Then you retain your history locally without pushing it to everyone else.
It depends.
Branches are permanently associated with a commit. The branch is part of the commit, and contributes to the hash. Changing the branch of a commit in the past would alter all commit hashes from that point forward. This is quite different from Git, where a branch is little more than an ephemeral pointer to a HEAD. Such pointers are implemented in Mercurial as bookmarks.
If the unwanted branches appear on commits which are (ancestors of) commits you want to publish, there is very little you can do, short of recreating the history with all-new hashes. This could (for instance) be done with hg export and hg import, along with local cloning and (probably) a certain amount of shell scripting. More efficiently, you could use the convert extension to automate the process. Since this changes commit hashes, it will likely cause serious problems if any of the commits have already been distributed publicly.
If you have no interest in sharing the offending commits, you can simply not publish them. This can be done with selective pushing. However, since you'll always have to manually exclude those commits every time you push, it's probably safer to clone and strip (or clone selectively with the -r flag). You can then push from your partial clone with impunity. Assuming you have a sufficiently recent version of Mercurial, you can also force the commits into the secret phase, so that they will not be pushed:
hg phase -fs revisions
You don't want to use hg strip, because it permanently removes the commits from the history (see Editing History in the Mercurial wiki)
If I were you, I would close the branches instead:
hg up -C badbranch
hg commit --close-branch -m 'close badbranch, this approach never worked'
hg up -C default
(source: Pruning branches in the Mercurial wiki)
After closing a branch, hg branches doesn't show it anymore.
If you do want to see closed branches, use the -c parameter:
hg branches -c
Disadvantage:
hg his still shows closed branches.
You could use the -b parameter though, to show only the default branch:
hg his -b default

How do you delete a commit in Mercurial?

I want to completely delete a Mercurial commit as if it was never entered in the repository and move back to my prior commit.
Is this possible?
If it was your last commit and you haven't pushed it anywhere, you can do that with rollback. Otherwise, no. Not really. Time to change your passwords.
Edit: It has been pointed out that you can clone from an older revision and merge in the changes you want to keep. That's also true, unless you have pushed it to a repo you don't control. Once you push, your data is very likely to be very hard to get back.
You can try to remove mq info about your commit.
For this you need to go File->Settings->Extensions.
There check mq and restart gui.
After that just right click on unneeded commit and
ModifyHistory->Strip
To edit the history I would use the Histedit Extension extension.
hg histedit 45:c3a3a271d11c
However keep in mind this only makes sense in a situation where you have not yet pushed the commits to the public repository, you own the public repository and/or you can account for all the clones out there. If you receive the following error:
abort: can't rebase immutable changeset 43ab8134e7af
It means that Mecurial thinks this is a public changeset (see phases) that has already been pushed - you can force it to be a draft again doing:
hg phase -f -d 45:c3a3a271d11c
I encounter this fairly often. I make a commit and then pull to push. But then there is something incoming that makes my newly made commit unnecessary. A plain hg rollback isn't enough because it only undoes the pull...
This is the thing to do:
hg strip <rev>
Things are painless when you don't push your changesets anywhere.
If it's more than one commit and/or you already pushed it somewhere else, you can clone your repository and specify the last changeset that should be cloned.
See my answer here how to do this:
Mercurial: Fix a borked history
If you only committed locally and didn't push, you can just create a clone locally (as described in my link) and you're done.
If you already pushed to some remote repository, you would have to replace that with your clone.
Of course it depends if you are able (or allowed) to do this.
You can use "hg backout" to do a reverse merge basically. All options are discussed in the freely available book "Mercurial: The Definitive Guide":
http://hgbook.red-bean.com/read/finding-and-fixing-mistakes.html
If using tortoise you can use modify history > strip...
Yes. Unless I am mistaken, as of v2.3 (rel. 2012/08/01) you can use the HisteditExtension with a drop command to drop a commit, along with strip or backout to remove changes.
A simple Google search on the feature: https://www.google.com/webhp#q=histedit+drop
In 2022 I do use evolve extension. It is one of the best extensions for this purpose.
To prune unwanted changeset, if you for example did a quick hack to get the code working:
$ echo 'debug hack' >> file1.c
$ hg commit -m 'debug hack'
Now you have a proper patch you can do hg prune .:
$ hg prune .
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
working directory is now at 2a39221aaebb
1 changesets pruned
If you push the change to the remote repository you will find only obsolescence markers:
$ hg push
searching for changes
no changes found
remote: 1 new obsolescence markers
To check the changes to your local repo you can pull from the remote one:
$ hg pull
pulling from ssh://userid#server/repo
searching for changes
no changes found