0

I used hg forget <files> to untrack some files without them being deleted from my file system like using hg rm <files> does. I committed the change and running hg status listed these files as being untracked ? <files> as expected. I then pushed the changeset to our remote repository, someone else pulled and updated, and mercurial deleted these files from their file system!

Why doesn't Mercurial recognize these these files as being untracked with hg forget on someone else's copy of the repository the same way it does in the copy the changes originated?

Is their another way of untracking files without them being deleted from anybody's file system?

Kevin
  • 367
  • 1
  • 2
  • 12

1 Answers1

0

Both Git and Mercurial have the same issue here: You have some commit O (an old one) in which there is a file F. Now you update from O to new commit N, which says "there is no file F".

What should the version control system do? Well, that depends on why F was removed, doesn't it? If we removed F because it was used before, but is now useless clutter, it should be removed.

So, why is removing no-longer-used correct but keeping accidentally-committed also correct? And how should the VCS know which of these two is meant, given that all it can see is that commit O has both no-longer-used and accidentally-committed, while commit N has neither file?

(Neither Git nor Mercurial have a good answer to this, as far as I know.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • Isn't the point of having `hg rm` and `hg forget` to tell it what you need it to do since it doesn't know? In my case I was untracking files whose content I thought was unique to everybody's local development environment. – Kevin Aug 20 '16 at 04:32
  • Unfortunately, the only difference between `hg rm` and `hg forget` is that the latter leaves the file alone in the work-tree. I have tried (off and on, never too seriously) to come up with a semantic definition for Git for what could go in `.gitignore` (same idea as `.hgignore`) to mark a file as "not versioned, but precious" (so do not delete it), but have not come up with semantics I like, much less a real implementation. – torek Aug 20 '16 at 04:43
  • I'm new to programming and VCS so this discussion may be a bit beyond my grasp, but I guess I don't get why they can't keep track of what command was used to untrack a file and at least warn people when they pull changes. There's a warning when you pull and try to update changes that aren't being tracked locally; I think you have to start tracking those files before updating, so why not warn that your tracking files that are now untracked, giving the option to untrack them locally before upating so they don't get deleted or forcing the update anyway knowing that these files will be deleted? – Kevin Aug 20 '16 at 05:03
  • You're making the assumption that one moves linearly from past to future: file *F* was in some commit and now isn't *and* was not specifically *removed*. But VCSes are all about jumping around arbitrarily. When we go linearly backwards, file *F* becomes *added*. If the untracked version matches the added version, should the VCS complain, or simply "add" the file by now tracking it? Then maybe we jump to rev 123, then to 9415, then to 337, etc.; in each case *F* either exists in the commit, or doesn't. Existing VCSes simply remove it when going from "exists" to "doesn't". – torek Aug 20 '16 at 05:18
  • This is also where the problem with just marking files as "precious" in a .gitignore or .hgignore directive comes in. That works when you're on the revision you just made: in *N*, file *F* is marked as precious, meaning the VCS should not remove it, even though we went from some version where it did exist to *N* where it does not. But then a future or past version may not have *F* marked this way, and the VCS may wind up removing it. – torek Aug 20 '16 at 05:21
  • Thanks, this gives me a better idea why VCSes are inclined to just delete files that have moved from tracked to untracked, I think. I do still find it a bit counter intuitive that `hg forget` is willing to treat the local repo where this cmnd originated differently than all other repos; I mean, they are designed to effectively deal with trying to update the working directory with changes to untracked files in it, so why not try to represent the exact changes someone chose to make as accurately as possible across everybody's copy? – Kevin Aug 20 '16 at 09:33
  • `hg update`? Then Mercurial is like, OK: `0 files updated, 0 files merged, 0 files removed, 3 files FORGOTTEN, 0 files unresolved`. Then you go, OK: `hg status` Then Mercurial responds with 3 `?`'s with the untracked file names, and you decide what to do next: leave the files, delete the files, or add them back and and try to get rid of the developer who untracked them in the first place, etc. – Kevin Aug 20 '16 at 09:33
  • It's a reasonable request, and hg at least has the *possibility* of handling it (because hg records directory operations, vs Git which does not). Unfortunately, as I mentioned before, hg seems to record this only as a "delete the file" operation. Essentially there are three front end commands that delete a file: `hg forget` (record deletion and do nothing to work tree), `hg rm` (record deletion and remove from work tree), and `hg rm --after` (record deletion once file is already gone from work tree). In all 3 cases, for others to get the file back they must extract it from a previous commit. – torek Aug 20 '16 at 09:53
  • Makes sense. `hg forget` was never introduced as a new feature, but just a convenient shortcut to `hg rm -Af`. It's maybe a bit misleading for someone new but don't mean to balk at the idea, since like I said, I'm not enough of an expert to weigh in too heavily on the matter. Now that I understand what it does, it's all good. If anything, this has just been my humble attempt to save a little face after screwing something up. Thanks again for helping to clarify everything for me! – Kevin Aug 20 '16 at 17:39