28

Here's my use case: I commit PNGs and other stuff in my Git repo. I would like to apply a specific process to every PNGs I would like to commit and this is the result of the process I finally want to commit (the potential modified PNG).

At the beginning I thought about a hook (like a pre-commit) but it's a little weird because the process will change the file so I will need to re-add it! And according to what I read, there is no pre-add hook (or something like that).

May be a solution is to create a git alias ? But I don't want to change - too much - the way people work, I'm searching for a smooth and transparent way.

If you have a clue... even if the clue is to change my process idea.

Labynocle
  • 4,062
  • 7
  • 22
  • 24

3 Answers3

10

You may want to consider a smudge & clean filter, with the clean being applied during the git add, and the smudge during checkout. These can be allocated by file type. Look at the 'git attributes(5)' man page and Git SCM book : Git Attributes.

anol
  • 8,264
  • 3
  • 34
  • 78
Philip Oakley
  • 13,333
  • 9
  • 48
  • 71
  • 1
    Hi @philip-oakley thanks for the reply, your solution seems to be the right one: The "clean" filter is run when files are staged. I will try to use it and tell you if it's ok! – Labynocle Sep 19 '13 at 08:05
  • the solution is ok but it's nice to rewrite file but a little complicated to process an image :) I need to investigate more – Labynocle Sep 19 '13 at 09:49
  • 2
    Since the page is quite long, it would be useful to summarize the method here (I have tries to use it, to no avail). – Eric O. Lebigot Sep 10 '18 at 14:18
  • So... how exactly does this answer the question? – Seph Reed Jul 18 '19 at 05:25
  • @SephReed The response indicates that you can set Git (attributes) up such that on every checkout it runs a 'script' or filter to convert the internal file to something more readable (or whatever). It is done by file type. – Philip Oakley Jul 18 '19 at 18:30
  • Ah. So you could have something that says "every `.zip` shall be exploded"? – Seph Reed Jul 18 '19 at 18:32
  • 1
    @SephReed It probably gets complicated for exploding `.zip`s because they may not re-combine the same way (a known issue with zips), but if, say, it is just to get an index/dir listing of the zip contents then that's not hard. Also if it's exploded, you'd need to know what else has to go back in when you have focus on a single file. Plus zips don't compact multiple similar files that well (so I'm told). – Philip Oakley Jul 18 '19 at 18:36
  • Maybe zip was a bad example. Compression just came to mind for this. Less specifically, you could have a file that transforms back and forth? – Seph Reed Jul 18 '19 at 18:37
  • 1
    @SephReed "file that transforms back and forth?" Absolutely. That's the whole purpose of the smudge/clean filter pair. https://www.juandebravo.com/2017/12/02/git-filter-smudge-and-clean/ gives one example usage. – Philip Oakley Jul 19 '19 at 13:18
9

There may be a good reason to use clean instead, but there's actually nothing preventing you from re-adding the files during the pre-commit hook, which is a bit more intuitive in my opinion.

Your pre-commit would look something like:

*run your PNG processing here* (after processing completes) git add *.png

The commit will then continue as usual. If you want to get fancy you can throw an exit 1 in there when something goes wrong with the compression, and it will stop the commit.

dlsso
  • 7,209
  • 1
  • 21
  • 31
  • This doesn't appear to work as intended: the pre-processing is done, but it is as if it were to late for `git add` to register any change (thus, changes seem to be frozen before this script). I tested this with a script that *generates* the added file, and that a commit done after the file was deleted: the commit message indicates that it was deleted (despite having been generated again and git "added"). – Eric O. Lebigot Sep 10 '18 at 14:16
  • It sounds like you've forgotten to take the processing time into account. I suppose I should have mentioned it in the original, but you'll need a way to tell when your processing is done and don't `git add` until then. You obviously won't register any changes if `git add` hits before the changes are even made. – dlsso Sep 11 '18 at 19:29
  • `git add` is only run after the preprocessing. Now, the preprocessing processes a .ipynb file but creates a .py file (which is versioned), without using stdin as normally required by git, so maybe that's why git doesn't see that the file has changed. – Eric O. Lebigot Sep 12 '18 at 15:50
0

I did something similar to disso, using gulp and gulp-git.

var git = require('gulp-git')

// ... other tasks

gulp.task('add', function(){
  return gulp.src('cdn/**')
    .pipe(git.add())
})

This add task is then called at the end of everything else. Then I have gulp set up with a pre-commit hook. Works like a charm.

So in your case, the full file might look something like:

var gulp = require('gulp')
var $ = require('gulp-load-plugins')()
var runSequence = require('run-sequence')

gulp.task('default', function () {
  return runSequence(
    'images',
    'add'
    )
})

gulp.task('images', function() {
  return gulp.src('app/images/**/*')
    .pipe($.cache($.imagemin({
      progressive: true,
      interlaced: true
    })))
    .pipe(gulp.dest('dist/images'))
})

gulp.task('add', function(){
  return gulp.src('dist/**')
    .pipe($.git.add())
})

(Note that I haven't tested it... I got the images task code from Google.)

MalcolmOcean
  • 2,807
  • 2
  • 29
  • 38