Git

Git logo.png
Git is the version control system CAEDM recommends for tracking changes in software projects. It fills a similar function to other versioning systems you may have used like CVS, Subversion, etc.
Git allows branching and merging different versions of your source code.

Git allows one or more people to work on the same source code at the same time, tracks each person's branches and committed changes, and helps collect and distribute these changes between team members. This allows individuals and teams more freedom to try ideas without affecting others until the developer is ready. If a commit introduces a new bug, git makes it easier to find where the bug was introduced, which then makes fixing the bug faster and easier. Fixing a bug is often as easy as checking out a previous copy of a file.

Git can also track non-text files like compiled binaries or digital images, with some caveats. For instance, Git will not be able to show you differences between binary files, nor are versioned binaries stored efficiently. Tracking changes to videos or large numbers of changing images is certain to make a Git repository quickly grow large and slow.

The following sections have CAEDM specific helps, and a short list of common commands for using Git. There is also a wealth of other Git tutorials and documentation on the public Internet. The following resources are very good places to start:

  • https://try.github.io - Git basics in 15-minutes using a Code School simulator. More advanced classes are available for a price from Code School.
  • https://git-scm.com - Git client downloads, the free "Pro Git" book, a few intoduction videos, blogs, etc. The authoritative source of all things Git.
  • https://git-scm.com/book/en/v2 - The online versions of the "Pro Git" book.
  • git help and man git - Git's manual pages.


Git Installation

Git is already installed on CAEDM Linux and Windows workstations.

You can also download git for your own computer at https://git-scm.com/download. The Git "Thumbdrive Edition" (runnable from a flashdrive) is available at the same location. Git is also available in your favorite Linux distribution's package repositories.

It is recommended to use the standard git tools, but there are many other git clients available. Such tools are not discussed here, and their use is left as an exercise for the reader.


Using Git in CAEDM

Git repositories (and/or cloned repositories) can be stored in your personal homespace (the "J Drive"), and can also be stored in a CAEDM Group allowing everyone in your group access to the same repository. Git supports several ways of accessing a repository from a workstation or remote computer. CAEDM recommends using Git over SSH because it allows access a repository in the same way from both on and off campus. Alternatively, Git repositories can also be accessed using plain-old file paths (e.g. J:\my_repo or J:\groups\my_group\my_repo); but doing so from off campus will require using the CAEDM VPN.

Before using Git with any of the various Git cloud providers, please consider the security needs of the project first. Many cloud providers make your repository contents publicly available to anyone and everyone. This could be disastrous if your project uses or develops any kind of sensitive data or proprietary intellectual property. CAEDM Groups limit file and repository access to just members of the group by default. If there is any doubt about the sensitivity of a project's files, use a CAEDM Group. Repositories can always be published later when the security question is understood. On the other hand, once the proverbial cat is out of the bag, it is very painful and perhaps impossible to the get the cat back in.


Git Started Personally

Personal Git repositories are created in your project's directory using git init. This will create a .git directory (where all of the git magic is stored). All of the files created in the project directory are then candidates for git tracking.

You can get a personal copy of an existing git repository by using git clone <repository path> in the directory of your choice. A new directory will be created that contains a full copy of the desired repository with all the .git magic.

Git has many powerful and helpful commands. The most commonly used commands on a personal repository are:

git init 
Creates a new personal git repository in the current directory. For groups, see Git Started in a CAEDM Group.
git status 
Lists the state of each file in your project's directory. Files can be untracked file, modified (but not yet staged for commit), or staged (ready to be committed)
git add [files] 
Tells git to add a file(s) to the staging area for a subsequent commit.
git reset [files] 
Used when you change your mind and decide that file(s) should not be staged for subsequent commit after all.
git commit [-m message] 
Does the actual work of committing files from the staging area into the personal git repository, and prompts for a commit message (if one was not specified). The default message editor is vim, but can be changed to your favorite text editor (i.e. emacs, GEdit, Notepad++, etc). Log messages can be quite helpful to yourself and your team mates, so consider making good, descriptive log messages. A log message like "Fixed some stuff." is not likely to be appreciated by your team mates or your future self.
git log 
Shows a log of who made what commit when, and the commit message that (hopefully) describes the changes. Each log message has a unique commit identifier consisting of a long string of hexadecimal numbers. If you need to use one of these identifiers in a git command, remember you don't have to use the full identifier. Git can infer which commit you mean from just the first 5 or 6 numbers in the identifier.
git checkout [commit] [files] 
Replaces the working copies of files with the with the versions from the specified commit.
git diff HEAD [files] 
Compares your working copy of specified files with the version in the most recent commit (aka the HEAD commit), using diff. This is useful for finding what code broke things, and for reminding you what changes should be in your commit message.
git difftool [-t favorite_diff_tool] ... 
Just like git diff, but allows you to specify your favorite diff-ing tool with the -t option. If you don't specify a tool with -t, git will try to find one for you. If it can't find a better diff tool, it will use plain-old diff. Options include vimdiff, kompare, emerge, meld, etc.
git help [command] 
Shows help documentation for the specified git command, or general git help if command is left off. Git has many options; if you can dream it, there is probably a git command or option to do it.

Git Started in a CAEDM Group

If you are creating a project that will be shared between multiple people, it is recommended to create a "bare repository" in a CAEDM Group. A bare repository contains only the magic files normally store in the .git directory, and does not provide editable copies of the project files. This becomes a central, authoritative Git repository, and team members "clone" their copies from the bare repository. The cloned personal repository then refers to the central bare repository as the "origin". New changes in the central bare repository ("the origin") are "pulled" into each team member's personal repository. Changes a team member makes and commits in their personal repository are "pushed" to the "origin" for distribution to everyone else.

Commands used on a bare repository:

git init --bare [path/to/desired/directory] 
Creates a bare repository in the desired directory. It is rare to use any other git commands on a bare repository.

Commands used when cloning or syncing with a bare repository (or "origin"):

git clone ssh://<user>@ssh.et.byu.edu//path/to/bare/repository/ 
Used to clone from a bare repository over ssh. Best for use both inside and outside the university.
git clone [path/to/bare/repository] 
When used with a user's directory ("J: drive"). Must use CAEDM VPN to access from outside the university.
git pull 
This retrieves changes from the "origin". Git can generally merges all changes automatically, but occasionally it will need help. If there are any merge conflicts from the same files being edited by different people a message will be printed stating so, and the conflicts must be manually reviewed and resolved. Once you have manually resolved any merge conflicts, you must run git commit once more to finish the original git pull operation.
git push 
Uploads all personal commits to the "origin", making your commits available to everyone else. It is generally best to do a git pull before each git push to ensure that you have all the latest changes and resolved any merge conflicts.
git mergetool [-t <merge program>] 
Launches vimdiff in 3-way diff/merge mode to help you manually resolve any merge conflicts. This is not frequently used but is nevertheless very helpful when it is needed. The -t option allows you to specify your favorite merging tool instead of vimdiff.

All other commands specified in the Git Started Personally section also apply to shared repositories.

Git Tips from the Trenches

The following tips are optional, but help a great deal when working in a team.

Learn to Use Vim (or change the default editor)

Vim (and the graphical version GVim) is a very powerful editor that is included by default in pretty much every Unix distribution (including Mac OSX), and is available for Windows as well. Git defaults to using Vim anytime an editor is needed, like when adding a commit message interactively. A 30-minute vim tutorial can be done by running vimtutor from a command line. Other online tutorials and videos are also available.

If you just aren't dazzled with Vim, you can change the editor Git uses. This can be done with git config. See man git config or git help config for details.


Use a Consistent Coding Style

Every developer has their favorite coding style, be it K&R, Allman, etc, and their favorite indent style. Source code is far easier to understand when the style is consistent. Consistent style also helps a great deal when comparing differences between versions of the same file. If style or formatting of a file has been changed to suit someone else's preference, seeing minor code changes can become very difficult.

When working with others on a team, pick a style together that everyone can live with. Then use a code beautifier (like astyle or perltidy) to ensure that your code meets the selected style before each commit. A properly configured code beautifier applied consistently has the added benefit of allowing people to code in their favorite style. Even languages like Python that have a strict style can benefit from consistent use of tabs or spaces for indenting, and consistent indent sizes across the whole project. Be open minded when choosing a style, and you just might discover a new style that makes your life easier.


Normalize line endings

Windows uses two characters, CRLF (Carriage Return and Line Feed characters) to end lines in a text file instead of just the LF character that Linux, Mac, and other Unixes use. This difference has caused a lot of grief in the past, and can cause significant grief with Git, and any other version control system. For instance, if a file is edited on two different platforms, it will end up with mixed line endings, will not display new lines properly, and will confuse Git merging and diff tools into thinking every line has changed when really only a few lines of the file changed.

Therefore it is a good idea to tell Git to normalize all line endings when commiting files, and restore the platform-specific line endings when checking out any commit. This can be done by setting the . gitattributes as one of the first files in your project's directory to something like the following and commiting that .gitattributes into the repository.

# .gitattributes
# This file helps normalize line endings.  Without this, line endings
# end up being inconsistent, and it makes merging and diffing against previous
# versions difficult.
#==============================================================================

# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto

# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.h text
*.java text

# Declare files that will always have CRLF line endings on checkout.
# Visual Studio solution files
*.sln text eol=crlf

# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary

These options can also be set with git config for some (or all) users of a machine, but using a .gitattributes file will ensure the same settings are used for anyone that clones your repository. It is not necessary to set these options if development will only be done on one type of platform. But using a small .gitattributes file early on will save a enormous amount of pain later if the project ever is used on a different platform.


Learn Three-Way Merges

At some point you are going to need to do a merge where the same file's lines have been changed by different developers. Git will insert conflict markers in the partially-merged files showing what each version of the contested area was. It looks something like this:

<<<<<<< HEAD:file.txt
Hello world
=======
Goodbye
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt

The "<<<<<<< HEAD:file.txt" marker indicates that everything up to the ======== marker comes from the HEAD commit's version of file.txt. Everything from ======= to the ">>>>>>> 77976da3...:file.txt" marker comes from the 77976da... commit's version of file.txt. Now you can make an intelligent decision of what should really be in that entire area. While you could open each conflicted file and manually resolve the conflicts, Linux and Mac can use git mergetool to do a three-way merge using vimdiff. Once inside vimdiff, using :diffget [LOCAL|BASE|REMOTE] and :diffput [LOCAL|BASE|REMOTE] is fantastic for quickly selecting and resolving merge conflicts. LOCAL refers to your repository's version, REMOTE refers to the other repository's (or branch's) version, and BASE refers to the common ancestor to both LOCAL and REMOTE. The bottom window is the result of your diffget/diffput operations and manual edits. When all conflicts in a file are merged, simply write the bottom window out with :w and the file is merged. More information on vimdiff can be had by running :help vimdiff from inside vim.

On Windows you will need to use git mergetool -t <tool> to use the merge tool of your choice. This preference can also be configured with git config so the -t option does not have to be set. It might also be possible to install GVim on Windows and configure it to be used for editing and merging instead of the vim that is packaged with Git for Windows. kdiff3 is another tool for Windows that can do three-way merges.