I have two branches named X and Y. X is previously created and y is the latest one. Now I am at branch 'Y' and I have modified some files. I need to commit the files which I have modified and I need to commit the changes to 'X' branch instead of 'Y' branch. How can I do this with Mercury Hg or Tortoise Hg? (How to Switch to 'x' branch and commit the changes?)
You could
Commit it to Y branch
Then transplant/grave it to X branch
Then strip changeset from Y branch
As result it's look like you commited it to X instead of Y
If you have not committed the changes then you should be able to do the following:
hg update X
hg commit
Unless you've changed some of the same files in the same places within the file, this should be sufficient. If you have, then your hg update X command should fail. You have a few options at this point.
You can use Mercurial Queues (mq).
You can put your current changes into a patch queue:
hg qnew stufftomove -e
You'll be presented with whatever editor you use to create a commit message. Go ahead and fill in your commit message with whatever you want it to be when it is ultimately committed. If you don't use -e, it will just create the patch queue with no commit message. Later you can make a commit message with hg qrefresh -e if you want.
After the patch queue is created, pop it off with:
hg qpop
Now move to the X branch:
hg update X
Now push the patch queue on. This will apply the patch file:
hg qpush
This can either go on cleanly, or if you did have merge conflicts, you'll get a message that .rej files have been created. Those show you the parts of the changes that could not be applied automatically.
If you have .rej files, manually apply the pieces that didn't work and then run
hg qrefresh
This will update the patch file with the new changes.
When everything looks like what you want it to, you can convert the patch queue to a real commit with
hg qfinish stufftomove
Your file changes should now be committed on the branch you want them to be on.
Alternatively, if you already committed the changes on the wrong branch, and have not pushed your changes (or had them pulled) to a remote repository, you can do this:
hg qimport -r <revision to import>
At this point, continue the above instructions starting with hg qpop.
If you can be more specific about the state of the files and branches, I can help more specifically. In any case, I hope this helps.
Side note: If you've got merge conflicts in the steps above and don't like dealing with .rej files, you can use hg rebase which will allow you to resolve the conflicts in your favorite merge tool (or whatever tool you've got configured). Hope this helps.
I use Shelving for such operation: https://tortoisehg.bitbucket.io/manual/2.9/shelve.html
While you're on 'Y' branch, put all your changes to shelf. Then switch to 'X' branch and restore changes from your shelf.
Related
I know that when you update to a previous revision, you create a new branch on your next commit. What happens when you clone an earlier revision? Will your next commit (or push) create a new branch?
The reason I ask is because our Tip is currently broken, so until it gets fixed, I was planning to do the following:
hg clone -r <prev_rev> <Tip>
# make changes
hg commit -m "my changes" -u me
# wait for Tip to get fixed
hg pull
hg merge
hg push
Will this work? Or will it end up creating a new branch or a dangling head? I would like to avoid doing either of these things.
Yes, that will create a branch, at least in the sense of having a "fork" in the history of the repository.
The branch will not be assigned a new branch name, but that in itself is not usually important in terms of understanding what the history will look like in a repository.
If your original repo was:
A-B-C-D
Then you do a hg clone -r C... and a new commit, you will end up with:
A-B-C-(D)
\
E
Now, since you have cloned only up to C, that specific local repository may not include D yet. But when you eventually synchronize it with another that will have to be dealt with. If you PULL, then you will get D in that clone. If you try to push HG will warn you about creating a new remote head for which the usual approach is to merge.
There is nothing wrong with this approach. If you need to work around an issue in tip for the time being, this is a reasonable way to do it. But you don't really need a new clone, you could just hg update C and work from there, which might be easier.
what would be an equivalent mercurial command (or workflow) for
git reset --mixed HEAD^
or
git reset --soft HEAD^
i.e. I want leave the working tree intact but get the repository back into the state it was before the last commit. Surprisingly I did not find anything useful on stackoverflow or with google.
Note that I cannot use
hg rollback
as I've done some history rewriting using HistEdit after the last commit.
Added to clarify:
After some rebasing and history editing I had ended up with A<--B<--C. Then I used HistEdit to squash B and C together, obtaining A<--C'. Now I want to split up the commit C' (I committed the wrong files in B). I figured the easiest way to do this was to get the repository back to state A (which technically never existed in the repository because of all the rebasing and history editing before hand) and the working tree to the state of C' and then doing two commits.
The right way to replicate git reset --soft HEAD^ (undo the current commit but keep changes in the working copy) is:
hg strip --keep -r .
-1 will only work if the commit you want to strip is the very last commit that entered the repository. . refers to the currently checked out commit, which is the closest equivalent Mercurial has to Git's HEAD.
Note that if . has descendants, those will get stripped away too. If you'd like to keep the commit around, then once you have the commit ID, you can instead:
hg update .^
hg revert --all -r <commit id>
This will update to the commit's parent and then replace the files in the working copy with the versions at that commit.
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
How do I view commits that are about to be pushed?
I'd made a local commit. Pull a change. And no it requires a merge.
I prefer not to merge and would like to undo the commit,
Pull,
Update changes,
Then commit again.
How do I do it since rollback only undo the last command which is pull?
That's really the way Mercurial works, and you shouldnt fight it in the name of a straight linear history, but there are tools that can edit history. Enable the rebase extension and just run hg rebase after your pull. It will move your local commit to the tip automatically in the simple case you described.
How do I view commits that are about to be pushed?
Use hg outgoing. That shows what hg push would have sent to the server. The opposite command is hg incoming, which shows what hg pull would have retrieved.
I'd made a local commit. Pull a change. And no it requires a merge. I prefer not to merge and would like to undo the commit, Pull, Update changes, Then commit again.
Like Mark says, you're looking for the rebase extension. Enable it with
[extensions]
rebase =
in your config file and then run
$ hg pull
$ hg rebase
to move your local work (this can be multiple changesets, not just a single as in your work around!) on top of the changesets you just pulled down.
How do I do it since rollback only undo the last command which is pull?
Please don't use hg rollback as a general undo mechanism. It's a low-level command that should not be used as much as it is, especially not by new users. The rollback command removes the last transaction from the repository — a transaction in Mercurial is typically the last changeset you made or the last changesets (plural) you pulled into the repository.
Let's say I have this:
hg clone public_repo my_repo
touch a b c d
hg add .
hg commit -m a a
hg commit -m b b
hg commit -m c c
hg commit -m d d
hg push
# let's say revX is the revision that added a
hg strip revX
In my repository's history, the commits are gone. However, if I try to do a push after the strip, it tells me no changes found. Can the strip be applied to the public repo?
EDIT: the question is just hypothetical :). I am not in this situation, I just thought it would be interesting to find out how this works.
You need to run hg strip there. If it's bitbucket repo, you can do it from the admin panel. If not, SSH.
This is not possible. You have to strip the public repo as well.
hg strip just takes away changesets. It does not perform an "adding" operation which could be pushed.
In the exact example you provide, you could just hg rollback on the public repo.
Let me pretend you're asking a slightly different question: I've stripped part of my repository history, how do I propagate this change to other dev's repositories?
Mercurial offers no way of propagating stripping in the same way it propagates adding changesets. So you have to come up with your own way.
Bitbucket, for example, has an updates list (on the repo summary page, if my memory serves me well). If you do a strip, Bitbucket displays there something like this:
Changeset 12345abcdef was stripped from the repository, please run hg strip 12345abcdef locally.
When we had to propagate stripping of part of an old branch in our shop, here's what we did:
Stripped the changesets on the server.
Created a batch file named strip.bat on the default branch of the repo containing the command we'd run on the server, i.e. hg strip 1234567890.
Told everybody that whenever they cannot push because “push creates new remote heads” for no apparent reason, this means they should run strip.bat.
In case we ever need to strip something again, we just add another hg strip in the batch file.
P.S. Yes it's better not to strip, e.g. use backout to commit inverse changesets. Sometimes that's not an option: if you mistakenly merged branch a into branch b when you wanted the merge b into a, you're trapped. Even if you backout the merge changeset on feature, the merged changesets from a are already marked as merged, and you'll have a hard time doing another merge of these branches.
The correct and safe way to remove unwanted changes that made it to the wild is to hg backout them.
Sometimes it is not possible to strip or backout a change, for example if it was a merge revision and you don't have admin access to the server. One method that does work is to branch the last good revision and then close the bad head.
hg up badrev^ (Go to the revision before the bad one)
touch dummy && hg add dummy && hg ci -m 'dummy' && hg rm dummy && hg ci --amend -m 'Fix accidental merge' (Create a second head with no changes from the good revision)
hg up badrev (Go to the bad revision)
hg ci --close-branch -m 'Close bad head' (Close the bad head)
hg push
I am working with a repository with stable and experimental branches. Sometimes I add a file on the experimental branch that is not yet ready for the stable branch. When I merge, I want to merge the changes in the files that are common to both branches, but ignore the files that don't exist on one of the branches.
Here's a simple example:
hg init
hg branch stable
(create file A)
hg add A
hg commit -m "Added A"
hg branch exp
(create file B)
hg add B
hg commit -m "Added B, which is really experimental"
(modify file A)
hg commit -m "Some changes to A"
hg update stable
hg merge exp
However I change the merge tool configuration, Mercurial always seems to take B along with the merge. Since it doesn't exist on the stable branch, it's never a conflict.
I could do the following:
hg update stable
hg merge exp
hg commit -m "Merged"
hg revert -r 0 B
but that requires me to know which files need reverting.
Any thoughts on the simplest way to make the merge ignore files that don't exist on one branch, and preferably do it automatically?
You cannot ask Mercurial to do what you want.
You do not merge individual files, you merge the entire branch, which means that all the files that are part of the branch becomes part of the merge. This is how Mercurial is designed and how it operates.
Now, you could revert/forget/delete the files you don't want before you commit, but then you're just setting yourself up for disaster later.
I recommend you separate things you want to keep from things you don't know if you want to keep so that you can merge one branch and let the other be separate for now.