Search code examples
gitemacsgit-rebase

Emacs Reverts Buffer to Weird Previous State with Git-Rebase


I'm using Emacs (23.3.1) on OS X. I'm issuing git commands from a terminal, not using any of Emacs' VC functionality. I have Emacs set up to refresh when files are modified, which is enabled by these lines of my .emacs file:

(custom-set-variables
 ...
 '(auto-revert-interval 1)
 ... 
)
(global-auto-revert-mode 1)

This has always worked as I expected; if I pulled, my Emacs buffers would update with the merges or conflicts as if I had quit the buffers and freshly loaded each one.

Recently I started rebasing (calling git-fetch and then git-rebase) instead of simply pulling (with git-pull), and I don't know if the issue actually has to do with git-rebase, but I certainly didn't notice the problem before then and do now.

So here's the problem: I update a file, commit the changes with git commit -am "...", run git fetch origin, then run git rebase origin/master (sometimes squashing commits together in interactive mode). Now that I've pulled in the remote updates, I go to edit the file some more, and find that it looks like I've lost all my recent changes. The first time it happened, I got very mad and cursed the rebase algorithm for somehow losing my changes, until I realized that the file was completely intact and it was just that Emacs had somehow reverted to the version of the file prior to the changes I'd just committed. I can always solve the problem by closing the buffer and loading the file again, but this is quite a pain to do every time.

Does anyone have any idea what the problem is?


Solution

  • I'm the original author of autorevert, however, I have to dig quite deep into my memory as I haven't worked with it for quite some time.

    I believe this boils down to a problem with the Emacs core function verify-visited-file-modtime, which auto-revert use to check if a buffers needs to be refreshed.

    This could be caused by a number of reasons:

    • This could be a race condition, where Emacs reads a file before it was completely written, but sets the buffer modtime to the end time. (When this occurs, Emacs has auto-reverted the buffer half-way, but a new auto-revert does not trigger to revert the final version of the file.)

    • If the two variants of the file have the same time stamp, then Emacs will not see the difference.

    I don't think that there is little you can do on the lisp side to get this working properly (without resolving to brute-force solutions). Emacs really need to atomically get a fingerprint of the file that has been opened and read into a buffer, and this can only be done from the core (which is something outside my area). Also, some file systems don't have a higher timestap resolution than one second, making it inherently difficult to use the timestamp to detect if a file has been changed.