I want to use git as a means of backing up and having a history of changes for configuration files of software that I'm using on my desktop. This would be a local repository with a local installation of git.
I am however unsure of these:
Is it possible to add a file to repository, as if it was in a different path than its real one?
My concern is that if I add files naively, by copying them to the repository and updating the repo, I'd end up using double the space for each file. While it isn't going to be a lot of space, I would still prefer a cleaner solution. I've looked into
git-add
,git-mv
andgit-filter-branch
but they don't seem to provide a clean solution to this. Bothadd
andmv
mechanics can be used to accomplish this task, but don't really get around the problem of duplicating files.filter-branch
seems way too big of a hammer for this task.
Is it possible to change the path of a file after it is added?
git-filter-branch
seems capable of doing this, but I'm unsure of the side-effects.
Would symlinks or hardlinks work to circumvent the need to copy the files, assuming git isn't capable of what I need explicitly? Would this work cross-platform, or does git handle links differently on different platforms?
edit in 2017 - accepted the answer I got because now that I understand git better, I realize there isn't a better solution than copying files or just having a git repo at a grandparent directory. The inelegance of that, means copying files is the optimal solution and symlinks/hardlinks are irrelevant to this problem. The comments and answer may be useful to someone looking for something similar but not the same, so I encourage checking those out.
From the discussion in the comments I conclude that the question really is:
In a big directory hierarchy (my complete home directory) I want to put selected files (configuration files) under git version control while most other files ("normal" files) are not in version control.
I have never done that, but 2 options come to my mind:
1.) Make the whole directory hierarchy a git working area, but by using .gitignore rules exclude all files unless they are explicitly included. So you need to list configuration directories or files to have them version controlled.
Here is a demo script that builds a small example directory hierarchy. Everything is excluded from git version control, except the configuration directories/files explicitly included (You can guess from the names, which ones they are.)
#! /bin/sh
time=$(date +%H-%M-%S)
mkdir example-$time
cd example-$time
touch a b c
touch conf1
mkdir d1
touch d1/a
touch d1/b
touch d1/conf
mkdir d2
touch d2/f1
touch d2/f2
mkdir conf-d
touch conf-d/conf1
touch conf-d/conf2
git init
cat >.gitignore <<EOF
# ignore all files
*
# but not directories (if a directory is once ignored, git will never
# look what is inside)
!*/
# of course .gitignore must never be ignored
!.gitignore
# list configuration files
!conf1
EOF
cat >d1/.gitignore <<EOF
# list the configuration files in this "mixed" directory
!conf
EOF
cat >conf-d/.gitignore <<EOF
# this is a configuration directory, include everthing...
!*
# ... but ignore editor backup files
*~
EOF
git add -A
git status
I have never done this in real life, but from the example it seems to work. However, when you have other git repos in your directory tree, you probably need to include them as submodules. There are all kind of pitfalls related to submodules, so it might get quite tricky in the end.
2.) You did not mention what filesystem you are on. If you are on a Linux filesystem you could use hardlinks. Create a git repo for your backup somewhere and add hardlinks for all configuration files.
This demo script shows the idea:
#! /bin/sh
time=$(date +%H-%M-%S)
mkdir hl-example-$time
cd hl-example-$time
touch a b c
touch conf1
mkdir d1
touch d1/a
touch d1/b
touch d1/conf
mkdir d2
touch d2/f1
touch d2/f2
mkdir conf-d
touch conf-d/conf1
touch conf-d/conf2
mkdir hl-backup
cd hl-backup
git init
ln ../conf1 .
mkdir d1
ln ../d1/conf d1
mkdir conf-d
ln ../conf-d/* conf-d
git add -A
git status
Again, I have not done this in real life and hardlinks always have their pitfalls. A program might unlink its existing configuration file and create a new one with the same name instead of updating the existing one (actually that might be a good implementation because it helps to avoid corrupted configuration files). So you would need a script that checks that all configuration files are still hard-linked. And because you cannot hard-link directories, you would need a script that searches for new configuration files in configuration directories. I don't know how git exactly behaves on checkout. So before having git modify (e.g. restore) a hard-linked backup file, make sure you have another level of backup. Don't try this on a production system unless you really know what you are doing.