2

Having a pre-add hook would be useful.

I'm trying to run clang-format as a pre-commit hook, but everything gets complicated when there're unstaged changes. This would not be an issue if I could stash ONLY unstaged changes, but alas git stash --keep-index does not do that.

Ari Sweedler
  • 807
  • 7
  • 25
  • Unless something else is running `git add` *for* you, you can retrain yourself to run `git xyz` where `xyz` is your own alias that runs clang-format first, then runs `git add`. (Not really an answer, since it doesn't help you retrain your fingers, nor eliminate the need to do that. :-) ) – torek Aug 29 '19 at 23:36
  • Can't you run clang-format in some sort of "watch" mode, or as a plugin of your IDE, so it formats files after you save them? Also, how does having unstaged changes "complicate" things? – CodeCaster Aug 29 '19 at 23:44
  • @CodeCaster *I* can configure vim to format on save, *I* can remember to run clang-format in watch mode (90% of the time), *I* can even code in accordance to the style guide by myself (ok this one was a blatant lie). But what I can't do is write a frictionless script to help my friends do that. I *can* sit them down and help them configure their editors (I've actually already done this :P). But the cleanest solution in my mind is a pre-add hook. – Ari Sweedler Aug 29 '19 at 23:50
  • Also, your question as stated ("Why not?") is considered off-topic by some, because the answer will be _"Because"_. Could you rephrase it to ask _"How to run a command before adding files to the staging area"_ or something like that? – CodeCaster Aug 29 '19 at 23:51
  • @CodeCaster And yeah! Great question. There are 3 versions of a file when you've staged changes. The previous commit (I'll call this `f_repo`), the staged file (I'll call this `f_staged`), and the workspace version of the file (I'll call this `f_work`). I cannot get the changes between `f_work` and `f_staged` s.t. the diff only shows the changed files. I cannot stash the changes in `f_work` to revert it back to `f_staged` cleanly (stash saves a diff between `f_repo` and `f_staged`, causing merge conflicts after formatting then stash popping) – Ari Sweedler Aug 29 '19 at 23:56
  • @CodeCaster Fortunately there's already an answer to that: https://stackoverflow.com/questions/18877877/how-to-automatically-invoke-a-script-before-a-git-add - if this question is bad and deserves to get closed then it deserves to get closed. If it gets closed, then I suppose I'll have my answer "there's no reason - it just doesn't exist." – Ari Sweedler Aug 29 '19 at 23:59
  • Note: `git stash` actually saves *copies* but the copies are converted to diffs by `git stash apply` so the end effect is the same. I think your best bet is to help others configure their editors to auto-format - that's roughly the same amount of work as helping them install a hook, after all. The clean filter trick is also an option (especially since clang-format can run in a streaming mode) but then there's this weird difference between staged and work-tree copies that you will spend hours explaining. – torek Aug 29 '19 at 23:59
  • @torek Asking for my best bet is lazy :P I can make that decision by myself. (Not that you guys don't have good opinions that I'm thankful for - it's just that if I saw a question asking "how can I enforce style for my team at work" I would not think it belonged on stack overflow). Also, there are clear benefit of making it a git hook rather than a per-editor configuration. With a `.git_template` folder, every time someone clones they'll have it. The fact that its editor agnostic is appealing to me. I'm being blocked due to my own ignorance, not due to technological limitations. – Ari Sweedler Aug 30 '19 at 00:05

1 Answers1

2

There's no reason. That's just the way it is.

If you want to make git support pre-add hooks, then you can use filters. In case it's not obvious from the documentation, here's what you'd have to do:

In a gitattributes file, you assign a filter for the paths you want to hit. For example, in .git/info/attributes you put:

*.c filter=myFilter

Then, in one of git's config files, you'll have to define the filter.myFilter.clean command. For example, in .git/config:

[filter "myFilter"]
    clean = $(git rev-parse --show-toplevel)/.git/hooks/pre-add

Now, every time you add a .c file, you will run the commands in pre-add.


(Remember to chmod +x your script if you want it to run, and that it's being invoked from a different script, so stdout won't be tied to your terminal unless you do something like echo "Hi, this is a pre-add hook" > /dev/tty)

Ari Sweedler
  • 807
  • 7
  • 25
  • This is a cool answer. Is there any way we can inject this on npm install in some way so that the DX for every dev is the same? – Walter Monecke Aug 12 '23 at 09:56
  • What are you npm installing? Are you npm installing git? Git configuration is definitionally not versioned. But you could have IT set up your employee machines with a configured and prepopulated [git template dir](https://git-scm.com/docs/git-config#Documentation/git-config.txt-inittemplateDir) to make every new repo they clone or create have this config. – Ari Sweedler Aug 14 '23 at 17:10