git-branchless
git-branchless copied to clipboard
`git reword` message file isn't recognized by Vim as being a git commit message
Description of the bug
Vim (and presumably other editors) have support for recognizing if the file being edited is a git commit message file. Vim handles this with filetype=gitcommit, and applies helpful highlighting and line wrapping. Vim does not recognize that the file opened by git reword is a "gitcommit" file.
Steps to reproduce:
- Set your Git editor to vim
git reword- Observe that Vim thinks this is a plain text file.
Possible resolution
Vim recognizes this by looking at the filename (https://github.com/vim/vim/blob/master/runtime/filetype.vim#L708-L709) -- e.g. when doing git commit, it edits .git/COMMIT_EDITMSG, and then Vim sees this and treats it as a gitcommit file.
It doesn't look like there's a great way to handle this with the current setup. dialoguer::Editor doesn't allow specifying a specific temporary file path. It does allow setting a specific extension (https://docs.rs/dialoguer/latest/dialoguer/struct.Editor.html#method.extension), which it passes to tempfile's Builder::suffix (https://docs.rs/tempfile/latest/tempfile/struct.Builder.html#method.suffix). The documentation here says "Path separators are legal but not advisable.", but when I tried in practice to call .extension("/COMMIT_EDITMSG"), it broke (on macOS, at least) because something was unable to find the file that tempfile apparently created.
It looks like the functionality provided by Editor is pretty minimal -- perhaps this could be pulled into the crate, and the path .git/COMMIT_EDITMSG could be used (so it would look exactly the same as regular Git to an editor).
Workaround
You can manually run :setlocal filetype=gitcommit to set the currently opened file as being gitcommit.
Expected behavior
No response
Actual behavior
No response
Version of rustc
No response
Automated bug report
No response
Version of git-branchless
git-branchless 0.3.12
Version of git
git version 2.30.2
Hi @elipsitz, thanks for reporting. cc @claytonrcarter in case they have some thoughts.
This seems pretty reasonable. Technically speaking, git reword might produce multiple commit messages separated with lines like ++ reword abc123 some message, but I don't see any reason why we shouldn't let vim treat it as filetype=gitcommit.
It looks like the functionality provided by Editor is pretty minimal -- perhaps this could be pulled into the crate,
Yeah, I thought Editor might save us some work, but we've had a few customization problems so far, so it seems like it would be better to write it ourselves at this point.
Yes, I've also wanted something like this. Here's my thoughts, in no particular order:
-
I just tried editting
.git/COMMIT_EDITMSGin Emacs and it too (viamagitthe mighty) treats it as a commit message w/ formatting, line wrapping, etc. -
Editorreally isn't doing very much for us here, and I think we can replace the relevant parts of it w/ a couple dozen lines of code, and doing so might make it possible to test this parts of the code that were not possible withEditor. (eg when the contents of the file aren't changed, or commits are added or removed during edit) -
... but
Editoruses a temp file, which makes file collisions unlikely. If we start editting.git/COMMIT_EDITMSGfor every reword, when we would need to figure out what to do if that file already exists. (Fail and ask the user to finish their other commit/reword or to remove it manually? Clobber it?) And we would need to make sure we clean up after ourselves, which maybe goes w/o saying. -
branchless rewordalready creates a file called.git/REWORD_EDITMSGwhen it encounters an error, so that the user can recover their work. So we already have some behavior that's adjacent to this, and it would be easy to update this to use.git/COMMIT_EDITMSG -
The only other option that comes to mind would be to include some sort of "file local variable" string in the file we create. Emacs supports this via file local variables, and I thought that vim had something similar builtin but I can't find it off hand. The downside to this is that -- if it even works for vim -- we'd probably be stuck including a different "local variable" string for each editor we want to support, and that doesn't sound like any fun.
I guess I'm thinking out loud, but it seems that I've talked myself into this:
- Reimplement
Editorw/igit-branchless - Use
.git/COMMIT_EDITMSG - If that file exists, fail w/ a message stating such, and ask the user to finish any other
commits orrewords they have open, or to just remove the file.
I was just playing w/ this to learn more about how git handles COMMIT_EDITMSG (at least as of git 2.32.0) and it turns that I had totally misunderstood how this file is handled:
- When creating a commit...
- If the file doesn't exist, it will be created.
- If the file exists, it will be overwritten w/o prompting.
- When a commit is successfully created or amended, the edited file is left in place. (ie it's not deleted upon success.)
- When the commit message is given on the command line (eg
-m 'Commit message here'), the contents of the file are (silently) replaced w/ the commit message given on the CLI.- This is the same for creating commits and for amending them.
This muddies the waters a bit, as I think that git reword is significantly more likely to error out than git commit. (We could error while trying to reword public commits, reword merge commits, "commit mismatch" issues w/ the message, etc.) This makes error recovery (ie work or message recovery) more important for git reword than for git commit. This means that we don't want to indiscriminately clobber the file every time (like git does) and risk losing work that users may want to recover, but also gits handling of this file means that the file will almost always exist, so erroring when it does (ie almost every time) would probably be obnoxious.
I'm not set on this (ie I'm 100% open to suggestions), but we may want to consider something like this:
- When staring
git reword- If the file doesn't exist, create it
- If it exists but doesn't contain any
++ rewordmarkers, clobber it - If it exists but does contain some
++ rewordmarkers, error out/prompt the user for direction
- When
git rewordexits- If no errors occurred, delete the file
- If any error occurred, leave the file in place
Another option might be to copy the existing file into a backup file each time we start a git reword, but then we'd need to be sure to remove old backup files periodically.
@elipsitz As a workaround, you could also just configure your editor to recognize REWORD_EDITMSG as filetype=gitcommit 😃
That doesn't actually help with this, right? Looks like that file is only created when there's an issue with git reword, not as the file that git reword opens in the configured editor.
@elipsitz Oops, you're right. But as an alternative to figuring out the rules for clobbering edit messages on disk, we could change git reword so that the temporary file (regardless of where it may be created) always uses the same basename or extension or something, so that it can be detected reliably by editors.
I forked and vendored the Editor code, so we can make this change now if we want.
https://github.com/arxanas/git-branchless/pull/791 changes git reword to name the file COMMIT_EDITMSG-*.txt, so you should be able to configure your editor to recognize that as a gitcommit file. It might even be possible to rely on the directory name being unique and then always call the file COMMIT_EDITMSG, which would make Vim work out of the box.
To configure Vim to use syntax highlighting after that commit, add this to your .vimrc:
autocmd BufNewFile,BufRead COMMIT_EDITMSG-*.txt set ft=gitcommit
Something I missed when I opened #791 is that if multiple commits are being rewritten then git reword will use an extended syntax where the separate commit messages are each introduced with a line like ++ reword <sha>. This doesn't necessarily interact well with standard COMMIT_EDITMSG formats, which tend to highlight text in the second line in red, since the first line in a commit message should usually be followed by a blank line. It might be worth naming multi-commit files differently, especially if the name for single-commit files becomes COMMIT_EDITMSG with no extensions.