Is there a way to collapse a few sequential Mercurial changesets into a tree view with a single description while maintaining full history? Kind of like rebasing, but displayed so that no history is altered.
These "fixed", "really fixed" and "really really fixed" changesets are driving me nuts.
Update: I found the Collapse Extension and the Histedit Extension, but both rewrite history like rebase. I wish there was a way of adding 'collapse' information with a commit message as a purely visual layer, without throwing away any changeset information.
No, there's no way to do this in mercurial. But what about having the extra changesets is bothering you? Your past code is always buggy, slow, and low-featured: that's why you kept developing it. There's no harm in having changesets that weren't quite right.
You can't control your repo's entire history; you can only change its current state. And if its current state has the bug fixed, there's no problem. Let the past be.
collapse a few sequential Mercurial changesets into a tree view with a single description while maintaining full history?
How you see it? One changeset with history of more-than-one?!
Short answer: No, you can't - or you have single collapsed changeset or you have rangeset
Longer answer: Not in single place, but at least in two it can be reached, if your repository wasn't published yet (because you can't edit history of already pushed repository - shared repository isn't under your exclusive control).
If repository with rangeset in question met the above requirements, you can try
Have one repo with unmodified history for development (hereinafter DEV)
Have one repo (clone of DEV) with collapsed history to sharing to public (hereinafter PUBLIC)
Suggested workflow:
Clone DEV (existing now) to PUBLIC
Collapse rangeset in PUBLIC by any preferred way (thus - rewrite it's history)
Publish PUBLIC
Continue your work on DEV
When needed, transfer changes to PUBLIC (you'll get anonymous branch with history, diverged at collapsed rangeset)
Linearize history on PUBLIC with rebase
Publish PUBLIC
Repeat 4 latest points in cycle during development
Related
I am new to Perforce and find it really hard to follow its workflow..
I have used Mercurial before (not in any advanced ways), but what I lack most in Perforce is the idea of named branches.
Let me explain what I'd like to do:
I get the latest revisions of all files and want to work on a new feature/story/task..
I create a brach, say "Feature 3021"
I code, save changes in this branch (hg commit)
I can save changes to a central server (hg push)
When I'm done coding, I merge the changes from "Feature 3021" with the main branch (default, master, etc.) - after that the main branch has the code I wrote
I can close the named brach ("Feature 3021") so that further commits are not possible.
I don't need this exact behavior in Perforce, but something analogous. I know that Perforce is centralized, so the commit-push step would be probably one, but this is a minor problem here.
All I care is to be able to save my work in version control at any time, even if it's not 100% ready - perhaps to a different branch. I'd also like other users to be able to be able to get my code (from this different branch), but only if they want this - the default branch should stay unafected as long as I don't merge my changes with it.
Is it possible? I am using Server 2012.2
Can you upgrade to Server 2013.1 or later? There's a great feature there, called Task Streams.
Here's some references:
http://www.perforce.com/blog/130627/task-streams-even-if-you-are-classic-perforce-shop
http://www.perforce.com/blog/130206/task-streams
http://www.perforce.com/perforce/doc.current/manuals/p4v/streams_task.html
The analogous flow in Perforce would be:
Maintain a main-line "branch" at some path, say //depot/default
To create a feature branch, integrate from //depot/default to //depot/feature-3021
Work under //depot/feature-3021 and submit
When you are ready to merge back, integrate //depot/feature-3021 to //depot/default
Regarding closing the branch after its use, there are a couple of options that I can think of. You could either change permissions or simply delete it. The delete could always be recovered.
Also note the paths don't need to be at the same hierarchy. A more reasonable branch strategy might use paths like this.
Main-line: //depot/default
Developer branches: //depot/dev/${user}/${feature}
I have an open source project on bitbucket. Recently, I've been working on an experimental branch which I (for whatever reason) didn't make an actual branch for. Instead what I did was use bookmarks.
So I made two bookmarks at the same revision
test --the new code I worked on that should now be abandoned(due to an experiment failure)
main -- the stable old code that works
I worked in test. I also pushed from test to my server, which ended up switching the tip tag to the new unstable code, when I really would've rather it stayed at main. I "switched" back to the main bookmark by doing a hg update main and then committing an insignificant change. So, I pushed this with hg push -f and now my source control is "correct" on the server.
I know that there should be a cleaner way to "switch" branches. What should I do in the future for this kind of operation?
tip is not a widely useful concept in a repository which has branches of any kind. Whether you are using bookmarks, named branches, or anonymous branches, tip always means the most recent commit on any branch, which is rarely something you care about. The real solution to your problem is to stop worrying about the tip!
I don't really understand your question, since you are switching (without quotes) branches, even if they are not named branches, they are still branches when you use bookmarks.
The mistake you had was an honest mistake and I see no way of having Mercurial protect you from doing that again with bookmarks (marking the same rev with different bookmarks and committing with the wrong one). What I can tell you though is how to do private local branching with Mercurial, and this way you can avoid having the consequences you just had:
You use named branches and phases
Mercurial Phases are really sweet, let me explain them real quick. You can mark revisions to three special states called phases, and these are: secret, draft and public.
secret: Don't get pushed. Can be modified through history editing.
draft: Get pushed. Can be modified through history editing. This is the default state of any revision.
public: Get pushed. Will issue a warning when using history editting extensions on them (strip, rebase, histedit,...).
As mentioned, all local revisions are draft by default, when you push them, they become public. You can use the hg phase command to mark revisions to a particular phase, but if you are going from #3 to #2, or from #2 to #1 (according to the previous numbering), you need the -f argument to force the change, this is:
secret --> draft --> public
To go to the left you need to use --force or -f.
Here is what you do:
hg branch experiment
hg commit -m "Opening experimental branch" //say this creates revision 123
hg phase -sf tip //s is for secret, f is for force
//... hack hack hack
hg commit -m "Uh oh screwed up here"
hg push //no secret revisions are pushed
Now, you can just abandon that branch and leave it like so, it wont ever get pushed. Forget about it and even just close it so that it wont bother you when you list your branches. It won't get pushed it won't get listed, so just don't worry about it.
However, if you have OCD, just strip (hg strip) the branch at the commit where the branch was opened, and it is gone:
hg strip 123
If you have an already existing branch, you can phase several revisions at once like this:
hg phase <start revision>::<end revision> -sf
To make your secret branch draft or public, just phase the latest revision to those phases:
hg phase -d tip //assuming you are in the experiment branch
Then push, and the branch will become public.
Mercurial has been increasingly becoming better at history modification without changing it's general philosophy of discouraging just that. Phases are meant to protect you from accidental history modification as well as from sharing what you don't mean to.
How *I* use bookmarks
Personally, I use bookmarks for debugging and for when I want to try 2 different ways of doing one thing. To me, bookmarks are useful when you want to do anonymous branches (update to a previous revision, commit and fork the history) but want to keep things intelligible.
I am new to DVCS's so please bear with me...
I am the author of a software library, currently hosted as a private repository on BitBucket. I would like to release the source code of my library to the public, but with the following setup:
I would like to maintain two repositories on BitBucket, a private one and a public one.
I would like the initial contents of the public repository to be the current contents of the private repository, without any history.
I would like to continue making commmits to the private repository without touching the public repository. Then, once in a while, I would like to take a whole bunch of commits to the private repository, and push them to the public repository, as a single changeset, and with its own commit message.
How can I pull this off? If it helps, my private repo only has one branch (the main one).
Concatenating changesets
Well, concatenating changesets can be achieved with one of these technics or with rebase extension with --collapse.
Branch structure
To do what you want you must have a development branch with the detailed commits and a publish branch with the concatenated ones. As long as the publish branch doesn't have any node from the development branch as ancestor, you can push only the publish branch. That means you would have to use one of the options above, you can't merge development branch into publish branch because that would set development branch nodes as ancestors of public branch and you would have to push those nodes.
Controversy
Although this is possible, I agree with #Ringding, it shoudn't be the routine workflow. Here are two good reasons for not doing that:
You are adding unnecessary complexity to your workflow, things should be simpler.
Those development changesets are the evolutive steps that led to the final version, they are part of the history, hiding that is like lying. That's why history editing tools are extensions and not core commands, they shouldn't be part of a normal workflow.
This is easy to do. I would create a "publish" branch and merge into that whenever you want to push to the public repo. Then use the convert extension to extract only this one branch.
However, it is almost never a good idea to work like this. Potential contributors usually don't want to put up with development behind closed doors. For open source work, it's usually best to open up everything – bug tracker, source repo, wiki, mailing list, reviews, …
Suppose I have the following senario:
Trunk is my main development line where programmers commit to when done.
Branch V1.0 is a branch I created when releasing version 1.0.
The programmer is working on the trunk but needs to switch to the branch in order to fix bugs.
When switching back to the trunk Subversion will give me the latest in the SVN repository which does not include the recent changes.
So, in order to switch he will have to commit what he has because otherwise the changes are "lost". I know they are still kept in the local repository but it would still mean restoring them one by one once he switchesback.
Am I missing something here?
Edit:
Now I am thinking down these lines:
Each programmer would have his own "private" development branch off of the trunch. He could commit to there whenever he wants. When he has finished what he has written he can them merge it into the trunk. He starts again for the next assignment.
If at any point he is required to fix a bug in some other release he can just commit to his own private branch, fetch the odl release and fix it. Then, after committing the changes to the fix, he can easily switch back to his own development branch.
Would that work?
I think that subversion is not thought for switching as you described. A solution would be to have two workspaces, one for the branch and another one the trunk, so you can switch from one to another without problems. I know it is not a nice one.
Consider switching to a version control tool that is better suited for your approach. My own suggestion is Mercurial, coupled with MercurialEclipse. The only drawbacks I'm aware of are that Subversion is better suited to store binary files and that Mercurial's subrepositories don't work so well as Subversion's externals.
In Mercurial your programmers would be able to commit their changes to their private repositories, merge and commit locally again, and then push the resulting changes to an official repository, from which other programmers would pull them into their own private repositories.
The best solution for such purposes is to have two separate working copies. One for working with trunk and one working with the branch.
I'm fairly new to Mercurial, but one of the advantages I see using Mercurial is that while writing a feature you can be more free to experiment, check in changes, share them, etc, while still maintaining a "clean" repo for the finished feature.
The issue is one of history. If I tried 6 different ways to get something to work, now I'm stuck with all of the history for all my mistakes. What I'd like to do is go through and clean up my changes and "collapse" them into one changeset that can be pushed into a shared repository. This is complicated by the fact that I might pull in new changesets from the shared repository, and have those changesets intermingled with my own.
The best way I know of to do that is to use hg export to create a patch of my changes since cloning, clone a fresh repository, and apply the patch to the fresh repository.
Those steps seems a little bit cumbersome and easy to mess up, particularly if this methodology is rolled out to the whole dev team, some of whom are a little resistant to change (don't get me started). TortoiseHg makes the process slightly better since you can highlight the changesets you want to be included in an export.
My question is this: Am I making this more complex than it needs to be? Is there a better workflow I can use to ease my troubles? Is it too much to expect a clean history where entire (small-ish) features are included in one changeset?
Or maybe my whole question could be summed up this way:
Is there an equivalent for this in mercurial? Collapsing a git repository's history
Although I think you should reconsider your use of branches in Mercurial (as per my comment on your post), using named branches doesn't really help with your concern of maintaining useless or unnecessary history - it just organizes them a bit.
I would recommend a combination of these tools:
mercurial queues
histedit (not distributed with Hg)
the mq changeset strip feature
to rework a messy history before pushing to a blessed or master repo. The easiest thing would be to use strip to permanently remove any changeset with no children. Once you've done that you can use mq or histedit to combine, relocate, or modify existing commits. Histedit will even let you redo the comment associated with a changeset.
Some pitfalls:
In your opening paragraph you mention sharing changesets during feature development. Please understand that once you've shared a changeset it's not a good idea to modify using mq or histedit, or strip. Using these extensions can result in a change to the revision hash, which will make them look like a new changeset to everyone else.
Also, I agree with Paul Nathan's comment that mq (and histedit) are power features and can easily destroy a history. It's a good idea to make a safety clone before using these extensions.
Named branches are the simplest solution. Each experimental approach gets its own branch.This retains the history of the experiments.
The next solution is to have a fresh clone for each experiment. The working one gets pushed back to the main repo.
The next solution - and probably what you are really looking for - is the mq extension, which can "squash" a series of patches into a single commit. I consider mq to be "advanced", and "subject to accidently shooting yourself in the foot". I also don't care to squash my commits - I like having my version history present for reference.