Mercurial - What are the steps involved to accomplish the rename of a branch after it has been created and committed to (both locally and in the central repo).
For example, I've created a branch called Zelda and then committed and pushed to a central repository. I now want to change the name of the branch to Triforce.
Is there an extension that accomplishes this? What might be the long way in addition to any extension solution?
The short answer is no.
The long answer is, Mercurial branches are names attached to changesets. If you have several changesets committed to the branch zelda and given away (i.e., pushed to the central repo), there's no way you can rename that branch without re-creating these changesets, which means rewriting history.
Even if you strip those changesets both in you repo and in the central repo, then re-create them as belonging to the branch triforce, and push the “renamed” branch again, all of your collaborators will end up having two copies of the changesets, one set on branch zelda, another on branch triforce.
So yes, what you should do is described in https://stackoverflow.com/a/7245187/67988. To quote from there, adjusted to your branch names, i.e. zelda is the old branch to be closed and triforce is the new branch to be created.
hg update zelda
hg commit --close-branch -m "mgmt: Close branch zelda"
hg branch triforce
hg commit -m "mgmt: Create branch triforce"
hg push --new-branch
P.S. If no one else pulled from the central repo yet, you can try stripping zelda from there. Or, if you have access to all other devs' PCs (assuming a controlled environment), and really want to go one very dangerous road, you can strip this branch from all the repos. This is definitely not considered good practice, and can only be used as a last resort measure.
The mutable-branches extension can give the illusion of having renamed a branch.
Related
How can I duplicate a branch in Mercurial? I need the new branch to be against head (as the first one is).
The GIT equivalent (if I was in branch-a) would be:
git checkout -b branch-b
A Mercurial branch is a named entity that consists of all the commits contained within the branch. So in order to duplicate some existing branch, you must also duplicate all of its commits to new commits that are in the new branch. We then get into metaphysics arguments about commit identity. It's probably not a good idea to go here at all, but if you do want to go here, use hg graft to copy all the desired commits into the new branch.
A Git branch consists of a name containing a raw commit hash ID. So duplicating a Git branch under a new name is trivial. Note that the set of branches that contain any given commit changes dynamically over time: a branch that was only on feature/tall may now only be on master, even though that commit is still that commit, even via most of these metaphysical arguments. (Only the "no identity over time" argument lets us claim that this is not the same commit.)
Another way to put it is that Mercurial's branches actually mean something, but Git's don't. If you need true branches, you can't use Git in the first place. Don't try to import Git's bizzareness into Mercurial: you'll just make your own life miserable.
Meanwhile, though, Mercurial contains a DAG just like Git. If you use Mercurial bookmarks, those work like Git branches. It's probably wiser, then, to just use bookmarks and be done with it.
If all else fails, see hg graft.
the new branch to be against head
What is this (in usual business-term, not Git-lingua)? While in common (and in details) #torek is totally right, he forgot to write exact command-set, something like
hg up <rev-id>
hg branch <new-branch-name>
hg graft -r "branch(old-branch-name)" --log
Summary: how to synchronize bitbucket with my local repo after having stripped a changeset locally from a branch which has been restarted?
Details:
My code in Mercurial has a default branch with the stable version. I create named branches to do some tests, eventually merging them into default if the changes are fine.
I created at some point a short-lived extratemp branch (one commit) which I abandoned. Later on I recreated a new branch also named extratemp. When committing, Tortoise Hg asked me if I wanted to "restart" the branch and I said yes (which was probably a bad idea).
I then decided to strip the old, short-lived, extratemp branch with hg strip -r 126 (where 126 was the short-lived changeset). So far so good, I now have the following view of the branches:
I then pushed to bitbucket and since it was reluctant :) I did a hg push --new-branch --force. Its view of the commits is the following:
As you can see it retained the bit I stripped (commit 5ac3e1b). If I now pull I get it back:
What can I do to force bitbucket to be synchronized with my local repo so that the original extratemp is not retained?
A strip cannot be synchronized, since it is the absence of a changeset. The original commit has been made public already, and it exists everywhere it has been pulled. Even if you remove it from the main repo, it may get pushed back again by another, eventually. If you want to remove it from the other repositories, you will have to strip it manually everywhere.
While this may be possible if the repo is private and if you control who has access to it, it can be harder for public repos. The best alternative is to leave the changeset while rendering it inactive.
To do so, simply merge the two heads of extratemp on your local repo, by following these instructions to the letter. Then, your branch should only have one head, with your current state.
THE CONTEXT:
There are three branches: "mine" and "yours" and "main". I started with a clean clone and the only requirement is to make the "mine" branch like the "main" branch with only a few added changes. I do not want to alter the other branches. The current "mine" branch has only one changeset that I would prefer to delete and replace with a new changeset.
MY ATTEMPT:
"mine" contains only one changeset, which I want to discard. So, I stripped this changeset(effectively deleting "mine"), updated directory to "main" branch, recreated "mine" ("hg branch mine"), added my changes, committed, and now I want to push. The output of "hg push -b mine" is "abort: push creates new remote head..." and references my new changeset. However, I just want to replace my new changeset with my old (locally deleted) changeset. "hg outgoing" lists my new changeset, "hg incoming" lists my old changeset.
I think I am very close, any suggestions? Would a forced push work here? Alternative solutions and helpful references are welcome.
After my attempt, which involved stripping the changesets that I did not want from the "mine" branch and then committing my new changesets on the "mine" branch, here is my solution:
I resolved this issue with a forced push "hg push -f" which thus created two heads on the "mine" branch (in the main repository), and then stripped the extra head using the "hg strip" extension. This was done from the main repository after I had pushed, which may not be perfect, but it worked for these purposes.
The forced push was needed to add my new changesets (the new "mine" branch) and the strip (which had to be done after the push, on the main repository) deleted the old "mine" branch. It turns out that stripping the "mine" branch in my local repository doesn't make a difference because the stripped changesets are still present on the main repository (thus the need to strip them after the push).
If there is a better solution (or a better way to phrase the question), I am curious to find out.
My use case is this:
I am working on a new feature and I have several commits on that feature.
Since it was a minor feature, I didn't even consider doing the feature in a feature branch.
However. Now my boss comes along and tells me to fix a bug on the same branch that I am working on (default).
To fix that I'd like to create a feature branch for my feature, push all my existing (unpushed) commits into that branch.
So I'd like to create a branch just before my first commit and then somehow move all my commits to that branch.
How can I do this?
There’s two ways to approach this, depending on your preference:
In a new repository.
Make a new clone of your repository, and do the bug fix you need to make there. Then push it to the main repository when you’re done, and continue where you left off in the original repository. Pull and merge to get the new changes as usual.
In the existing repository.
Update to the changeset before your local changes, and just start fixing and committing there. This creates a new anonymous branch. When you’re done, push using push -r ., this will only push the changes that are included in the working copy. After this, merge with your original branch (hg merge) and continue where you left off.
Note that you can bookmark the feature branch with hg bookmark if you do not feel comfortable with leaving your changes unlabeled. Also you can easily find back any heads you left behind using hg heads.
Personally I prefer to work in a new clean clone, as you don’t need to worry about branching and where to leave uncommitted changes. However if your project setup is complicated it may be more convenient to reuse the existing repo.
For this situation you can fix it by rebasing (which may need enabling in your configuration).
On your branch, update to the revision before the change-sets you want to move:
hg up -r<revison>
This assumes contiguous revisions need moving.
Create a new branch:
hg branch "TempWork"
Put a dummy commit onto it in order to get a new revision:
hg commit -m"New Branch"
Then perform the rebase from the first of the change-sets you want to move (it moves descendants automatically) and specify the new branch revision as the destination:
hg rebase -s<base revision> -d<new branch revision>
Then update back onto your main-line branch.
Fourth method: Using mq-patches
You have to have mq extension enabled and initiated for repo
On hotfix moment you
convert feature-commits into set of mq-patches (hg qimport)
Unapply all patches in set (hg qpop -a)
Code hotfix, commit
...
Finish and test hotfix on clean codebase
Apply all patches in set (hg qpush -a), fix possible conflicts
Convert patches back to changeset (hg qfinish)
We converted everything to Mercurial coming from CVS and so far so good. An issue we encountered today though is this situation.
Before the move to Mercurial I had a few pending changes from a while back, features that were started and later postponed for various reason. Odds are that someone else will finish those features months from now picking up from where I left off.
After cloning the new Mercurial repository I created separate branches to isolate those features.
It left me with something like this (made up rev. number)
hg update default
hg branch feature1
hg commit -m "Description of what I was doing in feature1"
hg update default
hg branch feature2
hg commit -m "Description of what I was doing feature2" (my tip is now here)
hg update default
hg push -f (to force the creation of my new branches, w/o affecting default, I haven't merged them)
During this the team have been working and pushing to our central repository so the default branch is say rev 40 (tip)
Now my push -f worked fine but positioned (tip) to my latest change -> 50:feature3 (tip). I was expecting the tip to stay at default on the central repository and just have my branches in there for someone to pick them up whenever. The graph also looks pretty funny when I use hgwebdir so I am pretty sure that's the wrong approach.
How would I do this? Should I close the branch first? Is tip actually important or just meta-data.
tip is always the most recent changeset added to the repository. From hg help revs:
The reserved name "tip" is a special tag that always identifies the most recent revision.
So long as the head of the default branch is what you expect, you'll be OK. No need to close the branch (but it's better to use hg push --new-branch if your version of Mercurial is new enough to support it).
tip is just an automatically-applied label referring to (I think) the most recent commit. Not a big deal; it's just there for convenience.
The tip label is pure meta-data and always points to the changeset with the highest revision number -- there is no more logic than that.
However, the fact that tip now points to a changeset on the feature branch wont cause you any trouble. When people make a clone, they will automatically be updated to the tip-most changeset on the default branch. So they can begin working right away after a clone. Furthermore, people who already have a clone will stay on their named branch when they run hg update. Here hg update takes you to the tip-most changeset on that named branch, e.g., on default if that is where you started.
People may think that hg update tip is the same as hg update, but that is only when there are no named branches at play. With named branches, giving an explicit revision name such as tip can changeset your named branch -- a plain hg update cannot.