I know this question has been asked and I know it´s against version control. But we have done some minor changes in the layout etc. and would like to remove the history of 30 revisions.
Is it possible to just remove these 30 revisions or merge them into one revision?
Like 160 was the last big one and then now we are on 195 but the 35 in beetween are all relatively small css changes so not really necessary for us. Is it possible to just get them into like 161 and then go from there?
I find using hg revert -r REV is a much easier approach that using histedit.
Don't do this if you have already pushed your changes.
Observe that the changesets that are being merged are all 'draft' phases.
Update to parent of the first changeset in set of changes you want to fold.
"hg revert -r REV -all" (where rev is the last change you want to fold) (ie. the tip - if its not the tip then you will have to do a rebase step between step 3 and step 4).
Commit.
Use strip to remove old changesets
And the final result:
It would be really nice to be able to do step 2 directly from the thg gui but I haven't found a way of doing it.
If you want to drop the revisions and all their descendants, you can just enable the strip extension, then right click->modify history->strip the changesets.
If you'd prefer to fold them together, and you haven't pushed yet, you can do this:
Enable the histedit extension in TortiseHG's settings.
Open a terminal with the terminal button.
Type hg histedit 160 and press enter. Replace 160 with the appropriate revision number. This part may take several seconds, so don't panic if the terminal seems to freeze.
A text editor window will open with a list of the changes since 160. Change the text in front of each line you want to merge from pick to fold, to combine that changeset with the one above it. You'll also be prompted to edit the commit message after each fold. You can use drop to remove the changesets instead of folding them.
If you have pushed, modifying history is more complicated; see hg phases for details.
Related
I've got my IDE set to commit locally every time I save anything. I'd ideally like to keep an uncensored record of my idiot fumblings for the rare occasions they may be useful. But most of the time it makes my history way to detailed.
I'd like to know a good strategy to keep that history but be able to ignore it most of the time. My IDE is running my own script every time I save, so I have control over that.
I'm pretty new to Mercurial, so a basic answer might be all I need here. But what are all the steps I should do when committing, merging, and reporting to be able to mostly ignore these automatic commits, but without actually squashing them? Or am I better off giving up and just squashing?
Related question about how to squash with highly rated comment suggesting it might be better to keep that history
Edit - My point here is that if Mercurial wants to keep all your history (which I agree with), it should let you filter that history to avoid seeing the stuff you might be tempted to squash. I would prefer not to squash, I'm just asking for help in a strategy to (in regular usage, though not quite always) make it look as much as possible like I did squash my history.
You want to keep a detailed history in your repo, but you want to have (and be able to export) an idealized history that only contains "reasonable" revsets, right? I can sympathize.
Solution 1: Use tags to mark interesting points in the history, and learn to ignore all the messy bits between them.
Solution 2: Use two branches and merge. Do your development in branch default, and keep a parallel branch release. (You could call it clean, but in effect you are managing releases). Whenever default is in a stable state that you want to checkpoint, switch to branch release and merge into it the current state of default-- in batches, if you wish. If you never commit anything directly to release, there will never be a merge conflict.
(original branch) --o--o--o--o--o--o--o (default)
\ \ \
r ... ... --r--------r (release)
Result: You can update to any revision of release and expect a functioning state. You can run hg log -r release and you will only see the chosen checkpoints. You can examine the full log to see how everything happened. Drawbacks: Because the release branch depends on default, you can't push it to another repo without bringing default with it. Also hg glog -r release will look weird because of the repeated merges.
Solution 3: Use named branches as above, but use the rebase extension instead of merging. It has an option to copy, rather than move outright, the rebased changesets; and it has an option --collapse that will convert a set of revisions into a single one. Whenever you have a set of revisions r1:tip you want to finalize, copy them from default to release as follows:
hg rebase --source r1 --dest release --keep --collapse
This pushes ONE revision at the head of release that is equivalent to the entire changeset from r1 to the head of default. The --keep option makes it a copy, not a destructive rewrite. The advantage is that the release branch looks just as you wanted: nice and clean, and you can push it without dragging the default branch with it. The disadvantage is that you cannot relate its stages to the revisions in default, so I'd recommend method 2 unless you really have to hide the intermediate revisions. (Also: it's not as easy to squash your history in multiple batches, since rebase will move/copy all descendants of the "source" revision.)
All of these require you to do some extra work. This is inevitable, since mercurial has no way of knowing which revsets you'd like to squash.
it should let you filter that history to avoid seeing the stuff you might be tempted to squash
Mercurial has the tools for this. If you just don't want see (in hg log, I suppose) - filter these changesets with revsets:
hg log -r "not desc('autosave')"
Or if you use TortoiseHg, just go View -> Filter Toolbar, and type in "not desc('autosave')" in the toolbar. Voila, your autosave entries are hidden from the main list.
If you actually do want to keep all the tiny changes from every Ctrl-S in the repo history and only have log show the subset of the important ones, you could always tag the "important" changesets and then alias log to log -r tagged(). Or you could use the same principle with some other revset descriptor, such as including the text 'autosave' in the auto-committed messages and using log -r keyword(autosave), which would show you all non-autosaved commits.
To accomplish your goal, at least as I'd approach it, I'd use the mq extension and auto-commit the patch queue repository on every save. Then when you've finished your "idiot fumblings" you can hg qfinish the patch as a single changeset that can be pushed. You should (as always!) keep the changes centered around a single concept or step (e.g. "fixing the save button"), but this will capture all the little steps it took to get you there.
You'd need to
hg qinit --mq once to initialze the patch queue repo (fyi: stored at \.hg\patches\)
hg qnew fixing-the-save-btn creates a patch
then every time you save in your IDE
hg qrefresh to update the patch
hg commit --mq to make the small changeset in the patch queue repo
and when you are done
hg qfinish fixing-the-save-btn converts the patch into a changeset to be pushed
This keeps your fumblings local to your repo complete with what was changed every time you saved, but only pushes a changeset when it is complete. You could also qpop or qpush to change which item you were working on.
If you were to try the squash method, you'd lose the fumbling history when you squashed the changesets down. Either that or you'd be stuck trying to migrate work to/from the 'real' repository, which, I can tell you from experience, you don't want to do. :)
I would suggest you to use branches. When you start a new feature, you create a new branch. You can commit as many and often as you like within that branch. When you are done, you merge the feature branch into your trunk. In this way, you basically separate the history into two categories: one in fine-grain (history in feature branches), and the other in coarse-grain (history in the trunk). You can easily look at either one of them using the command: hg log --branch <branch-name>.
We have 2,700+ revisions and it takes a good 30-45 seconds to load Mercurial when doing a merge, push or anything else with TortoiseHg. I'm wondering if there's a way other than straight up creating a new repository to clean up the revision history. Say, cut off files under revision 2,400 or so.
Not an answer to your question, but:
Maybe reducing "log batch size" to 100 (default is 500) in the settings helps.
Our 2300+ rev repo loads in 2-3 secs (off my 15k rpm SAS-disk, but never mind that), so I don't think your problem is many revs, really. There are much bigger repos out there. :)
Note that both Mercurial core and TortoiseHg developers are keen on finding performance bugs, so it might be worthwhile to ask on the mail-lists for assistance.
You can use the histedit extension to compress several changesets into one. Executing the histedit command on a range of revisions will spawn a text document that looks like this (from the histedit documentation):
pick c561b4e977df Add beta
pick 030b686bedc4 Add gamma
pick 7c2fd3b9020c Add delta
Edit history between c561b4e977df and 7c2fd3b9020c
Commands:
p, pick = use commit
e, edit = use commit, but stop for amending
f, fold = use commit, but fold into previous commit
d, drop = remove commit from history
Changing pick to fold for a certain changeset in the list above will fold it into the previous changeset. It will give you an opportunity to resolve failed merges and enter a new commit message as well.
WARNING:
Using histedit will modify the repository history, including hash IDs, which will cause problems unless you re-start each developer with a new repository clone after the changes have been made. Also, you would probably need to limit your histedit-ing to changesets with a single parent (ie: non-merge changesets).
The problem that I'm running into is that I have some code reviews to do, with ~10 commits per review. It's an active repo with constant commits from developers. I have TortoiseHg filtering my changesets so that I am looking only at the ones that I care about.
What I would like to see is the difference between the changeset before the first change, and the last (without all the non-related changesets showing). I simply want to see the final results of all these changes. I don't care that there was some horrible code in changeset 1, that was fixed in 3. I just want to see the diff of what ultimately got merged through all these changesets.
I feel like I'm missing the obvious, and this isn't a bright question. Nevertheless, I'm asking anyways. Anyone?
I'm not sure about 1.1.8, as I'm using the 1.9/2.0 candidate release, but I believe you could left-click on changeset1, right-click on revision3 and select visual Diff. This should open your diff tool of choice and only show you the diffs between the 2 versions.
When I did this in the newer tortoise, it opened BeyondCompare in directory compare mode, with revision1 on one side, and revision2 on the other.
Don't merge in between commits and diff off the developers clone between start and finish changesets.
Or If merges occured, update and merge everything and then take the entire codebase (or just changed files) and dump it onto a clean tip clone (make sure you are working with the same version to avoid overwriting anything). Recommit all at once.
Say, I made many changes to my code and only need to commit a few of those changes. Is there a way to do it in mercurial? I know that darcs has a feature like this one.
I know hg transplant can do this between branches, but I need something like this for committing code in the present branch and not when adding change sets from some other branch.
If you are using TortoiseHg 1.x for Windows, this feature is implemented beautifully right out of the box (no extensions required).
Run the TortoiseHg Commit Tool.
Choose a file for which you only
want to commit a subset of its
changes.
Click on the Hunk
Selection tab in the preview pane.
Double-click or use the spacebar to
toggle which change hunks should be
included in the commit.
For TortoiseHg 2.x, the Hunk Selection tab is now gone. In its place, is the Shelve tool. It has a few more features than the old hunk selection. Those new features come at the cost of some added complexity.
Note that there is no need to explicitly enable the Mercurial Shelve extension when using this feature. According to Steve Borho (lead TortoiseHg developer) in response to a different TortoiseHg question: "We have a local copy of the shelve extension and call into it directly."
For TortoiseHg 2.7+, this functionality has been improved and re-introduced. It is now built directly into the Commit tool:
Notice in the file list on the left that the top file is checked to indicate it will be included, the second file is unchecked because it will not be included, and the third file, Sample.txt, is filled (the Null checkbox indicator) because only select changes from that file will be included in the commit.
The change to Sample.txt that will be included is checked in the lower-right change selection portion of the image. The change that will be excluded is unchecked and the diff view is grayed out. Also notice that the icon for the shelve tool is still readily available.
MQ as Chad mentioned are one way. There's also more lightweight solutions:
Record extension which works roughly the same way as darcs record. It's distributed with mercurial.
Shelve extension which allows you to "shelve" certain changes, allowing you to commit only a subset of your changes (the ones that are not shelved)
I feel like I'm missing something because nobody has suggested this already.
The normal "hg commit" command can be used to selectively choose what to commit (you don't have to commit all pending changes in the local working directory).
If you have a set of changes like so:
M ext-web/docroot/WEB-INF/liferay-display.xml
M ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
M ext-web/docroot/WEB-INF/portlet-ext.xml
You can commit just two of those changes with...
hg commit -m "partial commit of working dir changes" ext-web/docroot/WEB-INF/liferay-display.xml ext-web/docroot/WEB-INF/liferay-portlet-ext.xml
Not super convenient from the command line because you have to hand-type the files to selectively commit (vs a GUI check-box process like tortoise) but it's about as straightforward as it gets and requires no extensions. And file-globbing can probably help reduce typing (as it would above, both committed files uniquely share "liferay" in their pathnames.
The Mercurial Queues tutorial is terrible for this use case. All the examples I have seen assume you have yet to make a commit and you are refreshing a single patch. Most of the time this is not the case, and you have 2 or 3 commits that you want to squash together or change in some other way.
Lets say you have this sort of history:
---O---O---A---B---C
The first example is to squash commits A, B, and C. First init mq:
$ hg qinit
Now we need to "import" the commits A, B and C into the patch queue. Lets assume they are the last 3 commits. We can use the "-N" revision syntax to import them like so:
$ hg qimport -r -3:-1
That means import as patches from 3 patches back up to the last commit. You can check the status of these patches with hg qseries. It should show something like this:
$ hg qseries
101.diff
102.diff
103.diff
Where the numbers 101, 102 and 103 correspond to the local revision numbers of the commits A, B and C. Now these patches are applied, which means the changes that they describe are already in the working copy. You can get rid of the changes the working copy and remove them from the history of commits, saving them in patch form only, by using hg qpop. You can either say hg qpop; hg qpop to pop changes C and B off the stack, or specify a patch to "pop to". In this case, it would be something like this:
$ hg qpop 101.diff
now at: 101.diff
You now have the patches for commits B and C in the patch queue, but they are not applied (their changes have been "lost" - they only exist in the patch queue area). Now you can fold these patches into the last one, i.e. we create a new commit that is the equivalent of the sum of the changes A+B+C.
$ hg qfold -e 102.diff 103.diff
This will show your editor so you can change the commit message. By default the message will be the concatenation of the commit messages for the changes A, B and C, separated by asterisks. The nice thing here is that hg qfold will tab-complete the patches if you are using bash and have the hg-completion script sourced. This leaves the history like this, where A+B+C is a single commit that is the combination of the 3 patches that interest us:
---O---O---A+B+C
Another use case is if we have the same sort of history as before, but we want to drop patch B and merge A+C. This is pretty similar to above actually. When you get to the qfold step, you would simply fold in the last commit rather than the last 2 commits:
$ hg qfold -e 103.diff
This leaves the change for B in the patch queue, but it is not applied to the working copy and its commit is not in the history. You can see this by running:
$ hg qunapplied
102.diff
The history now looks like this, where A+C is a single commit that combines changes A and C:
---O---O---A+C
A final use case might be that you need to apply only commit C. You'd do this by running the qimport as above, and you would pop off all patches you didn't want:
$ hg qpop -a
The -a flag means pop off all patches. Now you can apply just the one you do want:
$ hg qpush 103.diff
This leaves you with this history:
---O---O---C
Once you are done with all this, you need to finish off the queue fiddling. This can be done with:
$ hg qfinish -a
So there we are. You can now run hg push and only commit exactly what you want, or hg email a coherent patch to the mailing list.
Some time has passed. Seems the best option now is hg commit --interactive
You can use the record extension, which is distributed with Mercurial.
You need to enable it in your ~/.hgrc file first, by adding it to the [extensions] section:
[extensions]
record=
Then, just type hg record instead of hg commit, and you will be able to select which changes to which files you want to commit.
You can also use the crecord extension which provides a nicer interface to review and select the changes. (It is not distributed with Mercurial, though, and I've seen it occasionally mess up a commit so it's not completely bug-free.)
I believe Mercurial Queues fills this role for Mercurial. There's a pretty good tutorial linked there.
Try qct (Qt Commit Tool). It has a "select changes" feature that starts up a 3-way merge tool for you to undo individual changes. After you commit, those changes you "undid" come back.
I use commit-patch. It's a script that lets you edit the diff before committing. It's really nice with Emacs's diff-mode and vc-mode.
In the past I used crecord, but it has bugs related to unicode (actually the record extension has the bugs, which crecord depends on).
First you must forget everything you ever knew about GUI's and return to the commandline. Next from the commandline do this:
hg stat > filelist.txt
This pipes all your modified files into a text file called filelist.txt
Next edit your filelist to include only the files you wish to commit.
Finally commit using the fileset sytnax:
hg commit "set: 'listfile:test.txt'"
How do I revert a single hunk in Mercurial, similar to the way it's done in darcs, i.e. it asks me for each hunk and file whether I want to revert it? Is it possible using TortoiseHg?
Thanks
Actually mercurial refers to "chunks", at least in the Shelve tool. Which brings me to favorite way to revert them (and favorite features of TortoiseHg).
Just move the chunks you want to revert onto a shelf you create solely with the intention to delete. This works really well as long as the chunks are identified as you need them to be. If not, you've got no choice but to do something manually.
If you use TortoiseHg Workbench or VisualHg, it is very easy to get to the Shelve tool: there is a button next to the diff mode toggle buttons. If you are not familiar with shelves, do yourself a favor and start using it. It has saved me much aggravation when I've forgotton to commit early, or decided to leave out experimental code from a commit.
The record extension is inspired by darcs record. It will allow you to add only specific hunks to the next commit, i.e., the opposite of what you want. But you could add all hunks except the one you want to revert and then do a hg revert to revert it. A little backwards, I know... :-)
You could also do hg diff > patch; hg revert, edit patch to delete the hunk and do hg import --no-commit to reappy the patch. That is likely faster, but requires you to manually edit the patch. I've had great success with the Emacs diff-mode, but since you ask about TortoiseHg you might not want to use Emacs.
For reversing a changeset on a single file try:
hg diff -c | patch -R
That will reverse the changeset introduced by that revision on that filename. Now if the same darcs/git style cherry-picking behavior could be included in that somehow I would be very happy.