Why does mercurial's "hg rebase" command take so much time for a relatively large repository? - version-control

Even though the changeset itself is very small, when I do a "hg rebase" for a relatively large repository (say around 10GB) why does it so much time. What exactly goes on behind the scenes?

Two quotes from hg help rebase
If you specify neither "-s" nor "-b", rebase uses the parent of the working directory as the base.
+
If you specify base ("-b/--base"), rebase will select ancestors of base back to but not including the common ancestor with dest.
With used by you syntax and possibly DAG of repo selecting ancestors may be time-consuming task

Related

How to do a difficult rebase in O(n) rather than O(n^2)?

There's this difficult rebase that keeps stumbling on conflicts every other commit. In order to be able to resolve some confusing conflicts, I must sometimes --abort and check out the master branch to see what exactly is there (unconfounded by conflict markup, stuff rebased so far, or git's "ours" vs. "theirs" hell). Whenever I do this, I must subsequently re-resolve all conflicts up to that point. This makes the rebase effectively O(n^2).
Is there a better way?
(Note: it absolutely must be a rebase, this requirement is a given. Merging is out of the question).
First, the new (Git 2.30) new merge strategy: ORT ("Ostensibly Recursive's Twin") will be slightly faster.
But the all process would still be not O(n).
Second, do use the git worktree command in order to checkout master in a separate folder (without making a separate clone).
That way, you don't have to abort the merge in progress, and can compare with a copy of your working tree, on master branch.

Reconstruct / rebuild a mercurial repository

First off: I know that hg branches are immutable and they cannot be renamed. I am also aware of the existence of the mutable branches extension for hg. But I'd prefer a different approach, as I can never be sure that all of our developers have it installed and active, it's still "only" an extension.
My question: We have a repo with about 20 branches in it. Due to various reasons (inexperienced use, bad choices, experiments that became production environments) some of those branches were named badly and now our repo is a little confusing. What we'd like to do is rename a few of those branches, because obviously, the more we work with them, the more it's becoming a problem.
Do you have any suggestions? I already thought of a "tool" or some kind of script that recreates the whole repo from scratch, getting changesets of the old repo and committing them - with new branch names - to a new repo, "rebuilding" it. But before I go and waste time in writing something like that, I'd like to hear if there are other possibilities.
FYI: there are about 600 commits with frequent merges across the various branches.
You can rebuild the repository by doing a Mercurial to Mercurial conversion using hg convert. Enable the convert extension first and create a branchmap to do the mapping of branch names from old to new:
a-bad-name new-name
another-bad-name better-name
You can use that to map multiple bad names into a single good name, for example.
After the conversion, you will have a new repository with the same history, but with different branch names. The changeset hashes will thus be different and people will have to reclone (but I think you're aware of this already).

Using mercurial why would I ever want to merge without committing?

Perhaps I'm biased from years of svn but why would I ever want to merge with a different branch then make some changes before committing. The hg output itself suggests otherwise:
(branch merge, don't forget to commit)
Dear hg, then why didn't you just do it for me?
Because a merge operation is not guaranteed to produce correct output (automatic merges can use bad heuristics for how to deal with conflicts, manual merges can suffer from human error). Usually, what you will do is the following:
Merge.
Build.
Test.
If the test failed, fix the issue, go back to 2.
Commit.
Mercurial does not suggests otherwise, it 's just reminder: "All merge-related changes stored only on Working Dir, commit results into repository for permanent storing" and doesn't prohibit you to make some additional changes in code before commit.
But separation of tasks (merge and not-related to merge changes - i.e changes not initiated by merge-conflicts) into separate changesets is good idea anyway

Ignore one parent when pulling a merge commit

I want to pull a set of changesets from a certain branch in a remote repository. One of the changesets is a merge from another branch, which I don't want to pull. However, it will be pulled even if I specify the branch name:
hg pull -r REV -b mybranch REMOTE_REPO
Is there a way to pull this commit as a regular changeset, ignoring its other ancestors?
No, this is impossible. All changesets (whether they are regular or merge changesets) depend on their ancestors and cannot be pulled in isolation. This is a fundamental design decision in Mercurial.
Merging prematurely results in the annoying situation you describe — each branch is no longer clean and cannot be pulled without also pulling in other stuff. The best way to avoid this is to use rebase (if the development is local-only and thus elegible for rebasing) or to simply ask people to stop mixing unrelated things together until you can make a firm decision about what needs to be merged.

Easiest way to perform incremental merge in mercurial

I have a project, that have branched sometime. Both branches have had a lot of commits since the split, and I want to merge them into one. Simply merging the two heads is not enough because it has too many conflicts, and the merged branch is also unstable, and non-functional.
Therefore I want to incrementally merge the two branches. By incremental I mean I take the tip of one of the branches and apply the changes from the other one one at a time. Testing each merge, and continuing if everything goes well.
What is the easiest way to do this using mercurial?
You've pretty much outlined a strategy yourself. Assume you have two heads, named headA and headB. hg up -r headB to one of the two heads, then use hg merge -r X repeatedly, where X is a revision along the other line of development.
You can use hg log -r 'ancestor(headA,headB)::headA' to get a list of good candidates for these merges (depending on overall topology).
You can use hg transplant to pull specific changesets into a branch.