12

So I'm very comfortable with version control, and just thought to start tracking versions of my bash profile: ~/.bash_profile with the added benefit of being able to share my various aliases and such on GitHub.

Assuming that my .bash_profile file needs to stay in my home directory(I can't wrap it in a directory to track it alone like a normal file), what would be the best way to go about this? I don't want to initialize a git repo in my home directory, and have to ignore every other file present.

So what might be a good solution?

I suppose I could just make a copy of it in a separate directory and update it / commit it from time to time, but I'm curious if there's a good way to version control a single file in a populated directory?

1
  • 8
    Symbolic links are your friends.
    – Blrfl
    Feb 25 '17 at 19:21
11

Afaik, typically there're two ways of doing this: a) symbolic link b) syncing script. In both case, you have to create another repo (name it dotfile below) for bash_profile to be version controlled.

Use symbolic links

bash_profile gets moved to your version controlled dir(containing .git), $HOME/.bash_profile is a soft link ⇢ $HOME/dotfile/bash_profile.

$HOME/dotfile/bash_profile is where your actual bash_profile resides, see holman dotfile as an example.

Use syncing script

bash_profile stays in your HOME dir but it's only a copy of the 'latest' one . The latest bash_profile still lives in $HOME/dotfile.

Yep, it's a copy and paste approach, this is why you need some syncing scriptto save you from DRY work. see mathiasbynens dotfiles as an good example. His syncing script https://github.com/mathiasbynens/dotfiles/blob/master/bootstrap.sh.

Furthermore

As you suspect:

I'm curious if there's a good way to version control a single file in a populated directory

Version controlling a single file doesn't make much sense, copy & paste or just drop it into some cloud drives saves you much hassle.

The real point is that things don't get scaled this way, when the dotfiles in your $HOME grows, when you want to version control your favorite text editor's config(say vimrc), when you use SSH to work with multiple shell remotely, you might have zshrc, bashrc, fishrc etc.

This means in the long run you might want to version control all your dotfiles. Github's dotfile is a good starting point.

4
  • 1
    Hadn't heard of symbolic links before! That's exactly what I was looking for. Thanks! Feb 27 '17 at 19:23
  • Thanks for the very helpful answer. Lots of other good ideas for putting this and other dotfiles in a repo can be found here: dotfiles.github.io
    – kevinmicke
    May 28 '18 at 21:03
  • @kevinmicke Glad it helps :)
    – xlee
    Jun 28 '18 at 2:51
  • "Version controlling a single file doesn't make much sense" Super disagree. I have so many random env vars accumulated over the years, I have to keep comments on them to tell what they are. I would have much preferred to just have it tracked in git, with commit messages to explain context.
    – Alexander
    Oct 16 '20 at 15:38
3

Another solution would be to deport your specific configuration (as setting your own aliases or defining your own functions) to a different file than .bash_profile. This way, only your specific configuration will be versioned and you only have to source it from your .bash_profile.

Do it manually

Let's say this .bash_profile extension file is named bash_profile_ext and contained into the /path/to/bash/profile/ext/ directory:

At the end of your .bash_profile file you will have:

source /path/to/bash/profile/ext/bash_profile_ext

And only your /path/to/bash/profile/ext directory will be versioned.

Do it using a third party app

Even simpler (I guess :-)), I'm developing shprofile that helps you to manage your shell profile, by only focusing on your specific profile configuration. shprofile allows you to define all your specific profile configuration into a single directory, which can then be versioned. Note you can also manage several profiles for the same user.

Again, no need to version all your .bash_profile configuration, but only your added values.

2

I don't want to initialize a git repo in my home directory, and have to ignore every other file present.

Why not? You want to track a file in your home directory, thus your home directory should be under version control, too.

That doesn't mean that your home directory needs to be a git repository. Let me explain:

git repositories consist of two parts: a working tree (unless it's a bare repository of course) and the .git "database" directory. Usually the later is just a (hidden) sub directory of the former, but that's not strictly necessary. git supports using a detached working tree. Thus you can keep your home directory under version control but don't need to have it contain a .git directory that could confuse tools (vim, emacs, ...) or git itself.

Setting up:

cd ~
mkdir .dotfiles
cd .dotfiles
git init .

Now there's a ~/.dotfiles/.git directory. Use that but specify the home directory as working tree. This requires quite a long command line, thus an alias is a good idea:

alias dotfiles='git --git-dir ~/.dotfiles/.git --work-tree=$HOME'

To use it just use the above alias instead of git, e.g. dotfiles status.

Benefits:

  • no other tools necessary, just git
  • no symlink hell / out of sync situations possible
  • git repositories in sub directories below home are not affected in any way

I got this from this blog post(which has some additional Infos) and am using it without any issues. I don't, but with a simple line * in .gitignore you can get rid of the possibly huge amount of untracked files and safeguard yourself a bit against adding files to the repository that aren't meant to be added.

1
  • Good point! Besides might need to re-define some existing git* alias I guess.
    – xlee
    Feb 26 '17 at 23:47
0

For enterprise level IT configuration management, many are using Puppet. I recommend Puppet to clients as a cost containment and reliability measure. Here in the lab, we keep it simple.

Our main repository contains files needed to completely rebuild a crashed system or build a new user account, and the version control has been useful on several occasions. Git is fine with files and directories that start with a period as long as git is not configured to ignore them.

These are repository paths for system and application installation and configuration.

knowledge.resources/install.linux/std.fedora.dnf.sh (dnf installations) knowledge.resources/install.linux/font.install.info.te (font installation) knowledge.resources/install.linux/std.fedora.te (other install and config)

These are general user configuration files.

startup/linux.basic.user/.bash_profile startup/linux.basic.user/.bashrc startup/linux.basic.user/.vimrc startup/linux.basic.user/.gitmessage startup/linux.basic.user/.gitconfig startup/linux.basic.user/use.ls.al.to.see.dot.files.here

These are for remote accounts on servers.

startup/linux.remote/.bash_profile startup/linux.remote/.bashrc startup/linux.remote/.vimrc startup/linux.remote/.gitmessage startup/linux.remote/.gitconfig startup/linux.remote/use.ls.al.to.see.dot.files.here

These are for the root account.

startup/linux.root/.bash_profile startup/linux.root/.bashrc startup/linux.root/.vimrc startup/linux.root/use.ls.al.to.see.dot.files.here

I use zero-size files called use.ls.al.to.see.dot.files.here to remind me that the directory only LOOKS empty.

-1

One more idea: You can add your profile to a GitHub Gist and use a CLI tool (like this one) to update it.

Not the answer you're looking for? Browse other questions tagged or ask your own question.