Search code examples
gitdotfiles

Filter confidential information on git bare repo


I'm using a bare repository for tracking my dotfiles and trying to filter the passwords and API keys from some of the files.

.gitattributes

 some-dotfile filter=remove-pass

.git/config

 [filter "remove-pass"]
 clean = "sed -e 's/^password=.*/#password=TODO/'"

This works on default repositories but not in a bare.


Solution

  • The clean command is called upon checkin. By default, a bare repository does not have a work tree, and we cannot run git commit in it. So, the clean command in a bare repository is not expected to be invoked in most cases. Commands like git push and git fetch do not invoke the clean command.

    There is a case in which the clean command configured in a bare repository can work. But it's tricky and rare.

    git init --bare /home/me/foo
    # edit /home/me/foo/config
    [filter "remove-pass"]
         clean = "sed -e 's/^password=.*/#password=TODO/'"
    
    # create a non-bare repository
    git init /home/me/bar
    cd /home/me/bar
    touch some-dotfile
    echo 'some-dotfile filter=remove-pass' > .gitattributes
    
    # use the work tree of the non-bare repository and the gitdir of the bare repository
    git --git-dir=/home/me/foo --work-tree=/home/me/bar add .
    git --git-dir=/home/me/foo --work-tree=/home/me/bar commit -m'init'
    
    echo 'password=helloworld' > some-dotfile
    git --git-dir=/home/me/foo --work-tree=/home/me/bar add .
    git --git-dir=/home/me/foo --work-tree=/home/me/bar commit -m'test clean command'
    

    The 2 new commits are stored in /home/me/foo instead of /home/me/bar/.git as we specify --git-dir. Now check the content of the committed some-dotfile,

    git clone /home/me/foo -- /home/me/myfoo
    cat /home/me/myfoo/some-dotfile
    

    The cat command prints #password=TODO so we know the clean command takes effect. However, we would unlikely use a bare repository like this.