You inherited a huge codebase with thousands of commits?
And it's an ugly mess? Now you cannot just reformat all those files?
But you want to have future changes adhering to some sane style?
Well, your formatter surely has some Git integration... it doesn't?
In that case, you are in the right place!
git fmt-diff
shows how you could reformat just the lines touched in commits
(similarly to tools like git-clang-format, but you can use any formatter)
- POSIX compatible shell (e.g. Dash, Bash, KornShell, Git Bash for Windows)
- Git
- Vim (optional) - for config-less filetype detection
- a formatter program of your choice
usage: git fmt-diff [<options>] [<commit>] [--] [<path>...]
or: git fmt-diff [<options>] --cached [<commit>] [--] [<path>...]
or: git fmt-diff [<options>] <commit>...<commit> [--] [<path>...]
or: git fmt-diff [<options>] <blob> <blob>
options:
-h display this help and exit
--cached view the changes you staged for the next commit relative
to the named <commit> (which defaults to HEAD)
--staged a synonym of --cached
--color always show colors
--no-color turn off colored diff
--fmtprg-stderr show stderr from formatter programs
--warn-risky-stderr redirects warning about potential unsolicited changes in suggestions to stderr;
option not recommended as the warning blocks dangerous 'git apply'
--version print version of git-fmt-diff script
- Download git-fmt-diff file
- Set it as executable:
$ chmod +x git-fmt-diff
- Put it into any directory listed in
$PATH
variable
Configuration follows the rest of Git configuration, example ~/.gitconfig
:
# ... [user], [init] etc. ...
[fmt-diff]
formatter-c = uncrustify -l C -c .uncrustify.cfg
map-cpp = *.ipp, *.pp
ignore = site-packages/*, *.sh
[fmt-diff "=python"]
ignore = true # ignoring all Python files
[fmt-diff "=go"]
formatter = gofmt
# ^-- a program from $PATH
[fmt-diff "tests/*"]
ignore = true # don't check files under tests/ dir
[fmt-diff "extern/*"]
ignore = true # ignore all files under extern/ dir ...
[fmt-diff "extern/lib/*.c"]
ignore = false # ... but do NOT ignore C files from extern/lib/ dir
[fmt-diff "tools/hex/*.c"]
formatter = ! ARTISTIC_STYLE_OPTIONS= astyle -A3 -K
# ^-- use sh expression
[fmt-diff "extern/cpp_lib/*.h"]
ignore = false
filetype = cpp
formatter = ../ParentProj/.bin/astyle --indent=tab -A5
# ^-- relative path to executable
# ... [alias], [include] etc. ...
[fmt-diff]
- general sectionformatter-filetype
- formatter command for files with typefiletype
map-filetype
- comma separated list of glob patterns to map files tofiletype
ignore
- comma separated list of globs to ignore
[fmt-diff "=filetype"]
- configuration forfiletype
formatter
- format command for this filetypeignore
- ignore formatting for this filetype (values:true
orfalse
)
[fmt-diff "path/to/*/smt/*"]
- configuration for files under globfiletype
- map files matching glob to this filetypeformatter
- format command for files matching this globignore
- ignore formatting for files matching glob (values:true
orfalse
)
Your formatter command needs to read from stdio and write to stdout.
That implies command needing to be filename agnostic!
First word in formatter command needs to be an executable (either from $PATH
or a path to it).
Before running the command, script checks whether it's possible using test -x "$(command -v EXE)"
.
You can use sh expression instead if you start the command with !
.
All paths are in relation to repository root.
Globs in sections are primitive - relative path won't be handled correctly.