How to transfer blame from a deleted file to it's replacement? - mercurial

I started with the file OldController.php and converted it to NewController.php. Here's my workflow:
Commit: Delete OldController.php and create NewController.php
Amend: Do some work on NewController.php
Amend: Do more work on NewController.php
(Pretty sure the amends hold no relevance, but figured I'd mention them anyways.)
So, how do I take the history of OldController.php and point it to NewController.php?
I know I can just go back and do this manually, but I'd like to know how to do this within mercurial.

Update back to the last revision where OldController.php still existed. At that point, use hg mv to effectively rename it to NewController.php. Commit that rename. This creates a new head.
At that point you have a few options:
Merge the commit you just made with the other head which already had NewController.php
Rebase everything starting with the first commit to include NewController.php onto the new head you just created.
Either way would be effective, but it depends on whether you want to preserve the history of this change, or you're OK just to make it look like you had renamed it from the get-go.

Use hg cp (or hg mv if you only want to rename the file) instead of deleting one file and newly creating the other. That way mercurial knows that the new file is based on the old one and will display history accordingly

Related

How to add a file where a file has moved in Mercurial

I moved a file from a.txt to b.txt using hg mv
Then I created a new file called a.txt
I did it this way because I want to preserve the history of a.txt in b.txt, and a.txt is logically a new file so I don't want it to have any history.
And I want to do all of this in a single changeset / commit.
Can mercurial handle this?
When I try, my client isn't clean after committing for some reason, and it seems to think the file is still actually being deleted where it was moved from in the changeset. Or something.
it seems not possible with current control versions, most (all?) of them considering a moved file as if it was deleted and added but with the enhancement of keeping track of its history
therefore in the very same commit you cannot move it and at the same time start a new one with a name clash, or else it wouldn't account as "deleted" which is a requirement for it to be "moved"
OTOH, think about how it would look like the diff of such commit?
One workaround is to copy the original file instead of move it using hg cp. The only downside is that it preserves the history of a.txt and doesn't show it as having moved. However if preserving the history of b.txt is your primary goal, this may be good enough.

How to completely change an hg repo's structure

I have an hg (Mercurial) repo located at, say:
http://myhg:5000/projects/fizzbuzz
This fizzbuz directory has the following basic structure:
fizzbuzz/
src/
... thousands of source files
docs/
... lots of docs
tests/
... lots of tests
I am now completely re-engineering the fizzbuzz app. The new app's project structure will be completely different (from the top down) than the existing one:
fizzbuzz/
herps/
foo/
... thousands of foos
bar/
... thousands of bars
derps/
... lots of derps
It's essentially a brand new app. I guess one solution would be to delete the fizzbuzz repo and then create a new one and add my code to the new one. But I was wondering if there's a way to basically tell hg to erase everything in a repo (but not delete the repo), and then add in the new, re-engineered, content. Or some other way to elegantly swap out the new code base for the old. Ideas? Thanks in advance!
Sure, you can wipe a repository by deleting everything and commiting all the changes (all the deletions). If you ever need to restore or review the old code it will still be available by checking out the revisions prior to the deletion. Unless your repository is very large on disk this is probably the way to go--alternatively you can start a new repository for the new version and leave the current one as-is.
In either case deleting all the code and its history is typically unwise.
Take a look at the Convert extension. While it is, by design, not possible to change the history of your current repository, you can, via hg convert, construct a new repository based on the history of an existing repository. This is very useful for scenarios like you describe, where you need to refactor the file-structure to such a degree that the old history is no longer useful.
That said, consider just making the changes directly in your current repository. What actual benefit do you get by rewriting history? Make the changes now, and Mercurial will continue doing it's job of tracking where you came from.

Restore history to split repository

Rightly or wrongly (almost certainly wrongly) I've ended up in the following position:
We used to have one big mercurial repository. We have now moved a large portion of this code base in to a separate repository. Looking back, it seems we could have done this in such a way that kept the file history, but naively we simply copied the files in to the new repository.
We are now in a position where the two repositories have been split, but I want to attach the file history of the moved files to those in the new repository. The files have been deleted in the original repository - but this history obviously still exists.
Is there anyway to "pre-pend" the history of the files in the original repository to those in the split repository?
The convert extension allows you to convert a Mercurial repository to another one while excluding and modifying filenames (using the --filemap option).
So use the convert command twice, one for each split, and use a corresponding filemap which only involves the files supposed to be in the particular target repository.
If you already did commits in the split repos you do not want to loose, use the convert approach anyway and afterwards migrate your new commits made in the splits w/o history to your new split repos made with convert:
Suppose your old splits with lost history are os1 and os2 and your new splits made with the convert command are ns1 and ns2. Then in ns1 you would do
hg pull --force os1 (force is required because you pull from an unrelated repo),
hg rebase -s <first-new-commit-made-in-os1> -d <last-converted-commit-in-ns1> (rebase new commits onto your split made with convert)
hg strip <first-commit-at-all-in-os1> (discard everything you pulled from os1 but not needed anymore)
Do it similarly with os2 and ns2
I don't know about attaching the file history after you've already done the split, but if you can do it all over again this is one option:
In your original repository, go back to the last revision (REV) before you deleted the files:
hg up -r REV
Go up one level from the original repository and make two new clones:
hg clone OriginalRepo Split1
hg clone OriginalRepo Split2
Go into Split1, delete the files you don't want in that repository, and commit. Do the same for Split2. These two are now your new split repositories, both with a complete history. Of course, the history for all deleted files (even those you initially didn't want in the repository) will exist equally in both repositories as well.
If you've done a lot of work in your new repositories after you made the split, you might be able to add these to your Split1 and Split2 by using export/import (check hg help import and hg help export). Depending on the number of changes you've made, there might be better ways to do this (e.g. mercurial queues), but this is what came to my mind first.

How to diff two revisions of a file that got renamed in between and Mercurial doesn't know about the renaming?

I accidentally renamed a file outside of Mercurial. When I committed the change, Mercurial treated the change as two unrelated files (ie. a remove and a add). I need to go back to diff the two revisions but I don't know how to do so when Mercurial sees them as two respective files across different revisions. What can I do to diff the files?
You didn't say what operating system you were using. The following will work with bash on Linux:
diff <(hg cat -r rev1 file1) <(hg cat -r rev2 file2)
You can replace diff with another program like vimdiff if you want a visual diff.
If you want to actually fix the history so that Mercurial is aware of the rename (and can use that information in future merges if needed), there's a way to do so documented on the Tips and Tricks page on the Mercurial wiki.
Current contents copied here for ease of use (and in case the link gets broken later):
Steps:
Update your working directory to before you did the rename
Do an actual "hg rename" which will create a new head
Merge that new head into the revision where you did the "manual" rename (not the head revision!)
Then finally merge the head revision into this merge result.
Advice:
Make a clone first and work on that, just in case!
After finishing the steps, use a file compare tool to check that the original and the clone are identical
Check the file history of any moved file to make sure it is now restored
That being said, if all you want to do is compare the contents at the point in time, you can definitely accomplish that without making Mercurial aware of the rename (as mentioned in Stephen Rasku's answer). In fact, you can use a combination of "hg cat" and an external comparison tool to compare any files, not just ones that Mercurial knows about.
Fix history:
Update to first changeset with new-filename, save file outside WC
Update to parent of bad replacement changeset, replace file correctly (with rename tracking), commit, got second head
Rebase all changesets from old anonymous branch on top of fresh good changeset
--close-branch on bad-replacement changeset or delete this unwanted changeset or leave inactive head intact

Are deleted files still downloaded with an hg clone?

In our Mercurial repo we added a really big file (and did an hg push), then deleted the big file (and did another push).
Now if someone does an hg clone will they still pull down that big file? I know it won't appear in their working directory as it was deleted, but will the file still be pulled down and stored in Mercurial internal storage?
I'd like to ensure people don't have to pull down the file. I've learned that really big files should be stored outside of Mercurial, so I deleted the file. But I was wondering if people will still be pulling down the big file - in which case I guess I will recreate the repository from scratch.
Of course it will still be in the repository.
You can always update back to older revisions, and if you update back to the revision you got when you committed the file, it'll be there in all its glory.
There are two ways to mitigate this (when you're committing, not now):
One of the big-files extensions, these essentially add big files to a secondary repository and link the two, so that if you update to a revision where the file doesn't exist, and you don't already have it, it will not get updated. ie. it's more a "on-demand" style of pulling
If the file never changes, keep it available on the network and just create some kind of link to it instead of a full copy
Right now, you got four options:
Strip away the changeset that added the file, and all the changesets that came after it. You can do that using the Mercurial Queues extension. Note that you need to do this stripping in all clones. If just one of your users push back the repository that has that file in its history to the central clone, you have the changesets back.
Rebuild the repository from scratch manually
Using the hg convert command and some filtering, the --filemap option can be used for this
Leave it as is. How big is it, will be much of a problem?
Note that rebuilding the repository, either manually or through hg convert will invalidate all clones. Anyone trying to push to your new central clone from an old clone will get a message about unrelated repositories. If any of your users are stupi^H^H^H^H^Hnot smart enough to realize that forcing the push is a bad idea, then you will have problems with this approach.
Yes, the file is still in the history. If you want to delete it completely, you need to use Mercurial Queues — see Editing History on Mercurial wiki.
Just keep in mind this breaks clones as revision IDs change.