I'm using mercurial VCS, I've mistakenly pushed three commits and I want them to be undone, can this be achieved?
I'm pretty sure no changes were propagated to anyone from the repository I pushed to, so I'm confident that this won't break anyones code...
I've tried hg rollback but since I have pushed I cannot undo anything in the right way. Also I know about hg backout, but I'm not sure if I should use this one for what I need...
Thanks!
EDIT
This is the graph log, I forgot to mention that some commits were part of a merge, but they too need to be undone...
tip
|
a
| \
| b
| /
c
|
d
I need to return the tip to c, or d if there is no other way to prevent that because of the merge...
If it's already pushed, there are only two things that you can do now:
1) If you are able to delete the central repository and replace it by another one:
You can clone the central repository, but tell Mercurial to clone only up to changeset "c".
Then you can take this repository (which doesn't have the wrong changes) and replace the "old" central repository (the one which does have the wrong changes) with it.
Disadvantage: if someone already pulled the unwanted commits and later pushes again, they are in the repository again.
So you need to make sure that either no one pulled the mistakes, or everybody who did deletes his clone.
2) If option 1 is not possible, you can use hg backout to undo the effects of the wrong changes - not the changesets themselves.
Quote from the link:
Backout works by applying a changeset that's the opposite of the changeset to be backed out. That new changeset is committed to the repository, and eventually merged.
So the three wrong changesets will remain in the repository, plus another three will be added, each of them reverting the effects of one of the three wrong changesets.
If you do it like this, it doesn't matter if someone else already pulled the wrong changes...as soon as he pulls the three "backout" changesets as well, everything is okay again.
If you're positive the push is the last thing that happened to that remote repository, meaning neither you nor anyone else has pushed to it, you can login to that system and run hg rollback.
If it's a repository on a machine to which you can ssh you can run this command on your local system:
ssh you#there hg -R /path/to/the/repo rollback
As always please do be really careful with rollback. It undoes the last action on the repository without altering the working directory at all, and it's not always clear what the last action was. For example, this is datalosss:
...hack...
hg commit -m 'important work'
hg update somewhere else
hg rollback
Yikes!
Related
I have two branches let's say A and B. I have done few changes in A and committed my code into A then i have merged A into B and did a push.
Now the problem is i have added some unnecessary files into B.
I want o revert to a prev version of B. I have see few solutions to perform hg update -r and then forcefully push it to the repo which might lead to new heads which i don't want to do.
Bare me for the explanation, doing this for the first time. Thanks.
I want to revert back to 3313 revision
you can go on your head, remove the unnecessary files, commit and push.
Go to your branch B
hg update -r 3316
Remove the files, commit and push
hg forget yourfilethere
hg commit -m "Remove unecessary files"
hg push
let me know if it helps!
If what you want is to remove or modify a pushed revision, then I am afraid Mercurial (by design) does not support this. (You can change the phase of a revision to 'draft' and strip or amend it, but when you pull again the old revision will re-appear.)
If you really need to remove the revision (e.g. it contains some huge files), then there is nothing you can do about it on your local repository; the only way this can be done is on the remote repository (e.g. having the administrator run hg strip directly on the remote repository, or some equivalent thereof; the BitBucket interface does support stripping a revision).
We have had a similar problem at work, where some user committed very large files to the repository, and a lot of work was done on the repository afterwards. The only way we were to solve it was using the 'convert' extension to remove the files, and then pushing into a brand new repository. (If we had just pushed the converted repository to the existing one, this would just have created duplicate revisions starting from the point where the bad files were committed.)
I made some changes to a file and committed it. (In fact there were several commits).
Then I wanted to revert to the earlier version and lose all those changes.
I did something like:
hg update -r nnn where nnn was the reversion number of the changeset I wanted to go back to.
That worked. I was happy.
Then, later, I had to push my local repository to the remote. But when I did hg push I got a message about there being two heads on this branch and one of them not being known to the remote repositiory. It suggested I merge before pushing. (I think).
I googled this and found a page that suggested I do "hg merge". I did that. Now the resultant file is back to where I started. I.e. it contains all the changes I wanted to throw away.
Where did i go wrong?
EDIT:
I have found this post Mercurial — revert back to old version and continue from there
where it says:
If later you commit, you will effectively create a new branch. Then
you might continue working only on this branch or eventually merge the
existing one into it.
That sounds like my case. Something went wrong at the merging stage it seems. Was I on the wrong branch when I did "hg merge"?
You're past this point now but if it happens again, and it's just a single file you want to revert then consider:
hg revert --rev REVISION_YOU_LIKED path/to/just/one/file.txt
That doesn't update you whole repository to a different revision, and it doesn't create any commits. It just takes a single file in your working directory and makes it look like it used to. After doing that you can just commit and you're set.
That's not the way to go if you want to undo all the changes you've made to all files, but for reverting a single file use revert and avoid multiple heads and merging entirely.
No, nothing went wrong at the merge stage – Mercurial did exactly what you asked it to...
What merge means is that you take the changes on your current branch, and the changes on the 'other' branch, and you merge them. Since your original changes were in the 'other' branch, Mercurial carefully merged them back into your current branch.
What you needed to do was to discard the 'other' branch. There are various ways of doing that. The Mercurial help pages discuss the various techniques, but there are pointers in other SO questions: see for example Discard a local branch in Mercurial before it is pushed and Remove experimental branch.
(Edit) Afterthought: the reason you got a warning about there being two heads on the branch is because having two heads is often a temporary situation, so pushing them to a remote repository is something you don't want to do accidentally. Resolutions are (i) you did mean to push them, so use --force to create two heads in the remote repository; (ii) ooops!, you meant to merge them before pushing, so do that; or (iii) ooops!, you'd abandoned the 'other' one, so get rid of it. Your case was (iii).
I have a commit i pushed earlier today that i learned i had messed up on by not adding the correct files before pushing. I fixed the revision and re-pushed it, so now i have a revision containing literally nothing new and my real revision. This could really confuse my other team members working, so i would like to either merge both together or remove my 'blank' revision.
Here is a picture of my problem:
http://img525.imageshack.us/img525/3929/revisionproblem.png
Note that i cannot undo/rollback, it tells me the transaction is not available.
If you've pushed it there's very little you can do. You could hg strip it from your local repo, but you'll get it back the next time you pull. You could edit history with hg histedit or merge two changesets with hg collapse, but none of that will get rid of the changeset you've pushed.
That said, the comment in your screenshot, "I just rolled back my latest push...", has me thinking you might have hg push and hg commit confused. They're entirely different and hg push can't be rolled back (locally). A hg push sends your local changesets out to the world -- no takebacks. A hg commit creates a new local changeset.
If you've misstated your problem and you've merely hg commited a changeset you regret you have all the extension-based options I listed above available to you. If you've really pushed it -- welcome to DVCS usage: once it's out there it's out there, and the best you can do it correct it in a subsequent commit.
If I have a bunch of uncommitted changes and want to set it aside while working on something else instead, and then later (f.i. after several days) come back to it and proceed working. What would be the easiest workflow to accomplish this? (So far I have only experience with Mercurial's basic functionality). My usual method was to create a new branch using clone, but there might be better ways.
You have a handful options:
Shelve the items. This saves the changes and removes them from the working directory so the branch can continue. It doesn't create a change-set.
hg shelve --all --name "UnfinishedChanges"
hg unshelve --name "UnfinishedChanges"
Update/Edit: Newer versions of mercurial may need to use
hg shelve -n "UnfinishedChanges"
hg unshelve "UnfinishedChanges"
You can still use --name as an alternative to -n, but mercurial doesn't seem to like --name anymore. Additionally, the --all is no longer required and mercurial will in fact freak out over it.
Patch queue the items using mq. This isn't too dissimilar to shelve in some respects, but behaves differently. The end result is the same, changes are removed and can be optionally re-applied later. When pushed, the patches are logical change-sets, when popped they are saved elsewhere and are not part of change-set history.
hg qnew "UnfinishedWork"
hg qrefresh
hg qpop
hg qpush "UnfinishedWork"
Commit them locally, update to the previous change-set and continue working and make use of anonymous branches (or multiple heads). If you then want the changes, you can merge heads. If you don't want the changes, you can strip the change-set.
hg commit -m"Commiting unfinished work in-line."
hg update -r<previous revision>
hg strip -r<revision of temporary commit>
Commit them to a named branch. The workflow then becomes the same as option 3 - merge or strip when you are ready.
hg branch "NewBranch"
hg commit -m"Commiting unfinished work to temporary named branch."
hg update <previous branch name>
Personally I use option 3 or 4 as I don't mind stripping change-sets or checking-in partial code (so long as that doesn't eventually get pushed). This can be used in conjunction with the new Phase stuff to hide your local change-sets from other users if need-be.
I also use the rebase command to move change-sets around to avoid merges where a merge wouldn't add anything to the history of the code. Merges I tend to save for activity between important branches (such as release branches), or activity from a longer-lived feature branch. There is also the histedit command I use for compressing change-sets where the "chattiness" of them reduces the value.
Patch queues are also a common mechanism for doing this, but they have stack semantics. You push and pop patches, but a patch that is "underneath" another patch in the stack requires that the one on top of it be pushed also.
Warning, as with all these options, if the files have more changes since the temporary changes that you've shelved / queued / branched, there will be merge resolution required when un-shelving / pushing / merging.
Personally, I don't like any of the answers posted so far:
I don't like clone branching because I like each project to have only one directory. Working on different directories at the same time completly messes the history of recent files of my editors. I always end up changing the wrong file. So I don't do that anymore.
I use shelve for quick fixes (just to move my uncommited changes to another branch, if I realize I'm at the wrong one). You are talking about days, no way I'd shelve something for days.
I think mq is too complicated for such an ordinary sittuation
I think the best way is to simply commit your changes, than you go back to the changeset before you start these changes and work from there. There are some minor issues, let me illustrate:
Let's say you have the changeset A. Than you start your changes. At this point you want set it aside for a while. First of all, commit your work:
hg ci -m "Working on new stuff"
If you want, you can add a bookmark to make it easier to come back later. I always create bookmarks to my anonymous branches.
hg bookmark new-stuff
Go back to the changeset before these modifications
hg update A
From here, you work and generate the changeset C. Now you have 2 heads (B and C), you'll be warned when you try to push. You can push only one branch by specifying the head of that branch:
hg push -r C
Or you can change the phase of the new-stuff branch to secret. Secret changesets won't be pushed.
hg phase -r new-stuff --secret --force
To keep local uncommited changes, easiest way for me is just to save them as a patch file.
hg diff > /tmp/`hg id -i`.patch
and when you need to return to previous state:
hg up <REV_WHERE_SAVED>
hg patch --no-commit /tmp/<REV_WHERE_SAVED>.patch
You can just clone your repo multiple times. I tend to have a root clone, then multiple childs from there. Example:
MyProject.Root
MyProject.BugFix1
MyProject.BugFix2
MyProject.FeatureChange1
MyProject.FeatureChange2
The 4 childs are all cloned from the root and push/pull to/from the root. The root then push/pulls from the master repo on the network/internet somewhere. The root acts as your sort of personal staging area.
So in your case, you'd just clone up a new repo and start working. Leave your 'shelved' work alone in the other repo. It's that simple.
The only downside is disk space usage, but if that were a concern you'd not be using DVCS at all anyway ;) Oh and it does kind of pollute your Visual Studio "recent projects" list, but what the hey.
[Edit following comments] :-
To conclude then... what you're doing is completely fine and normal. I would argue it is the best possible way to work when the following are true: 1) it is short-lived 2) you don't need to collaborate with other developers 3) the changes don't need to leave your PC until commit/push time.
I forked someone elses repository on Bitbucket and made some changes (and pushed them to my forked repo). In the meantime, the original author made substantial changes (pretty much a rewrite).
I want to update my repo to be exactly the same as his (but with my changes still present on that tag) in a way that he can easily pull my new changes without the previous changes I made affecting anything.
I pulled his changes into my local version, which left me with 2 heads. I want to just take his head as the tip/default. I tried to resolve this (based on some SO answers) by doing:
hg update -r [myrev]
hg commit --close-branch
hg update -r [hisrev]
This seemed to put me in a state I wanted. My working directory looks like his. However, when I tryed to hg push I'm told this will create multiple remote heads, and I'm not sure if this is what I want (the message makes it sound scary!)
So, have I done this correctly? Should I force the push? Will this do what I want (eg. keep a copy of my changes so I can get to them, but in a way that generally won't interfere?). If so, was this the best way to achieve this?
Heads on a closed branch are still heads, so if you want to push those changes you'll need --force.
The other option, is to merge that head into what you want to be your default branch, but select none of its changes. This can be done non-interactively using:
hg update [hisrev]
hg --config ui.merge=internal:local merge [myrev]
hg commit
You'll be down to one head, and it will have only his content, but yours is still available in the history.