Git Simplified
This page details some of how I have set up my Git repositories. Managing Git in all of its various uses can be a massive project; luckily, I am only interested in a small subset of its capabilities. What I am looking for is as follows:
- Offsite repositories
- Single user (although potentially from multiple machines)
- Simple branching / merging
- Offline repository access
- Simple and secure access; I don't want to set up a separate daemon for remote connections. SSH is preferable.
Prior to this I have used Subversion, which fulfilled all my requirements with the exception of the Offline Repository. I frequently work on my programs when I am away from an Internet connection, and I don't like to go too long without a commit for fear of losing something or needing to revert. Unfortunately, Subversion does not support this easily.
Enter Git. From the home page, Git is 'a free & open source, distributed version control system designed to handle everything from small to very large projects with speed and efficiency'. There are many FAQs, HowTos, and tutorials which serve to describe Git's functionality. However, these are all much more in-depth than I need. Below are some of the common commands I use, with explanations on what is actually happening.
Server Side
To create a git repository on your server, create a directory (convention is to have the directory name end in .git) and create a bare repository in it:
mkdir ~/path/to/repository.git
You should see the confirmation "Initialized empty Git repository in <repository>".
cd ~/path/to/repository.git
git --bare init
Make sure that you set up this repository with the same user as you plan on accessing it with (or at least with a user which has read / write permission). Since we will be using SSH to access the remote repository, whatever SSH user you use needs to have access to this folder.
Client Side
The first time you use Git on a given machine, you will need to set up some defaults. My preferred preferences are below:
git config --global branch.autosetupmerge true
This will allow git-merge to merge changes from the remote branch automatically (useful when working on multiple machines)
Once you have created the server repository, you will need to populate it. The easiest way to do this is from the client. First, get your project set up (create an empty directory with a README file, a new Eclipse project, whatever). Navigate to the root directory in that project, and create a new git repository:
git init
You then should add whatever content you have, and commit to the local repository:
git add .
git commit -m "Initial commit"
Next we want to get set up to push the changes to your remote repository. To simplify this, we will add it as a named remote path. The convention (and the default for many remote commands) is to name your primary remote repository to be 'origin'.
git remote add origin ssh://myhost.example.com/~/path/to/repository.git
(Note that this step is only needed when you first initialize the repository; once that is done, and you want to clone it to another machine, the clone command will automatically add a remote path named origin.)
Push the contents of your local repository to the remote one:
git push --all origin
If there are changes on the remote repository (for instance, pushed from a different user / machine), you can fetch them with the pull command:
git pull origin master
To clone your remote repository (for instance, if you started work on another machine), you can use the clone command:
git clone ssh://myhost.example.com/~/path/to/repository.git
This will create a folder called 'repository' in the current directory, create a folder '.git' (the actual repository) in that folder, and clone the repository from the remote path to the local one. As mentioned earlier, it will also create a named remote path called 'origin' which points to the remote repository.
To get a patch for submission via email (for instance if you don't have write access to a repo), use the format-patch command:
git format-patch origin
where 'origin' is the repository where you are comparing your changes. You must have already committed your changes to your local repo. This will create one numbered file for each commit you have made.
Once you have submitted the patches and the main developer has committed them, you need to be able to get your repo back in sync with the main one. The easiest way to do this is to reset your commits and pull. To reset your commits, use the reset command:
git reset <commit>
where 'commit' is the commit stamp (or a unique portion of it) where you want to revert to. Generally this will be the last commit which was pulled from the main repo.
Other useful commands
Below are other commands which I have used on occasion, but which are not needed for daily repository usage. I record them here so I will not forget them.
Remove foo and bar from all previous revisions of the master branch, and force push to the server. This is useful if you want to remove files completely from history which have been committed a long time ago, such as passwords. This must be done on a per-branch basis. NOTE: This is a potentially very dangerous operation; be sure you have a backup of your repository!
git filter-branch -f --index-filter 'git rm -r --cached --ignore-unmatch foo bar' master; git push --force
Delete a remote branch. This is essentially pushing null on the local side and making it be the new named remote branch.
git push origin :branch
Move the entire repository starting from HEAD into a subfolder. This can be useful for merging multiple repositories into a single one, each in its own subdirectory. You can repeat this for different branches if you want multiple branches to end up the same way.
git filter-branch --prune-empty --tree-filter '
if [[ ! -e new-subfolder ]]; then
mkdir -p new-subfolder
git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files new-subfolder
fi'