Can't Hard Link the gitconfig File
Asked Answered
C

4

7

I am attempting to create a git repository to store all of my dotfiles and config files. My idea was to simply create hard links to all of the files I cared about and store those links in their own directory that I could turn into a repository.

I've hit a bit of a snag though with my ~/.gitconfig file. It seems that whenever I run the 'git config' command the link that I created no longer points to the right location e.g. the file in the repository no longer updates properly.

Here is an example using the shell and interactive ruby to determine the files linked state.

# Create the link
$ ln .gitconfig .conf_files/gitconfig  # Create the link

# The files are in fact linked
[1] pry(main)> File.identical?('.gitconfig', '.conf_files/gitconfig')
=> true

# Update the gitconfig file by running a 'git config' command
$ git config --global alias.last 'log -1 HEAD'

# The files are no longer linked.
[2] pry(main)> File.identical?('.gitconfig', '.conf_files/gitconfig')
=> false

I assume this has something to do with the way that git is writing the .gitconfig file. Does anyone know why this would happen, or have any creative ideas for a workaround?

Cerise answered 2/8, 2012 at 22:16 Comment(6)
git config breaks hard links. Use a symbolic link instead.Dentate
@William Pursell Correct me if I'm wrong but I don't think git recognizes symbolic links?Cerise
Put the actual file in the git repository, and then put a symbolic link to it in $HOME. git will never see the soft link.Dentate
@WilliamPursell: Git records symlinks as symlinks, not as the pointed-to file.Oblique
@WilliamPursell unfortunately if you make the actual ~/.gitconfig file a sym link then git will simply overwrite it when you run the git config command same as with a hard link.Cerise
@Matt, that's okay. The file is updated, and running git diff shows the update. Then you can commit the change. @Dietrich, git will never know the soft link exists. git sees a hard link to the file (probably the only one), but when git reads ~/.gitconfig or when bash reads ~/.bashrc, they follow the link to the file in the repo.Dentate
C
6

Try Eli Barzilay's solution in his comment at http://www.xxeo.com/archives/2010/02/16/dotfiles-in-git-finally-did-it.html:

So I’ve finally found a solution that takes the best of both: put the repo in a subdirectory, and instead of symlinks, add a configuration option for “core.worktree” to be your home directory. Now when you’re in your home directory you’re not in a git repo (so the first problem is gone), and you don’t need to deal with fragile symlinks as in the second case. You still have the minor hassle of excluding paths that you don’t want versioned (eg, the “*” in “.git/info/exclude” trick), but that’s not new.

Coastal answered 2/8, 2012 at 23:52 Comment(1)
This works great! It fixes the problem of every path being recognized as a git repo for git commands, avoids the problems of needing to use links of any kind, AND you don't have to clutter up the root of your file system. I just moved the contents of the .gitignore file in my answer to .conf_files/.git/info/exclude and it worked like a charm. Thanks a lot for this!Cerise
O
2

This is completely normal, and is in fact the recommended way to overwrite config files. Git creates a temporary file, writes out the config, and then moves the new file over the old one. This way, you don't get an incomplete config file (data loss) if Git gets interrupted.

You can always write a script to copy or link your config files into your central repository.

Oblique answered 2/8, 2012 at 22:21 Comment(3)
That would make sense as to why the hard links break, but I was hoping there might be a simpler/cleaner way to keep the files identical.Cerise
@MattGarriott: The real issue here is that you are trying to use Git to keep track of files that cannot be in the Git repository itself. That's just a fundamental limitation of the way filesystems are designed these days, and the way Git is designed. I would consider a script a "simple and clean" way to do this. Git is a bunch of scripts anyway. The alternative is to make Git keep track of files outside of its repository -- while this is technically possible, you would need to know your way around the Git plumbing.Oblique
You are absolutely right, and that's why I have decided to approach this problem from a different perspective, I've attached my new solution as an answer to this question. Thanks for all your explanations and help!Cerise
B
0

Checkout this answer, perhaps it may be of help:

https://mcmap.net/q/172758/-git-and-hard-links

In the meantime, have you considered doing the links in reverse? Create your repository full of config files, etc, and then in the place that you actually use your files, create a hard link to the 'real' file, which sits in the repository.

Bail answered 2/8, 2012 at 22:23 Comment(2)
Hard links are symmetrical. They do not go in reverse because they do not go forwards in the first place.Oblique
Ah that does appear to be a bit of a snag.Bail
C
0

Thanks to Dietrich Epp's answer and advice I have decided to approach this problem from a different angle by creating the repository at the root of my filesystem, and using .gitignore to track only the files I am interested in.

My .gitignore file now looks like this:

/*

!/etc/
/etc/*

# etc files
!/etc/rc.conf
!/etc/asound.conf
!/etc/mercurial/

!/home/
!/home/matt/
/home/matt/*

# Home files
!/home/matt/.xinitrc
!/home/matt/.gitconfig
!/home/matt/.bashrc

# Vim files
!/home/matt/.vimrc
!/home/matt/.vim/
.netrwhist

In addition to not having to copy the files separately and keep them in two separate locations this has the benefit that should I need I can easily revert the changes without having to manually copy the files as well.

Thanks for the help guys!

Cerise answered 2/8, 2012 at 23:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.