Not much of "slides", granted, but the Asciidoc source for the HTML file we were using is attached.

And because I keep dropping off and having to log back into my email I am going to keep this short.

Thomas Berezansky
Merrimack Valley Library Consortium




Local Customization Management - Why Git isn't just for developers
==================================================================
:numbered:
:toc:
:icons:

Git is a wonderful tool that the Evergreen developers use to keep track of the 
changes in Evergreen and OpenSRF. It allows for multiple developers to work on 
the same area at the same time and in many cases figures out most of what was 
intended automatically later.

And that power isn't just useful to developers. Git is a Version Control 
System, in that it keeps track of multiple versions of files. New versions of 
files such as, say, the customizations being made to an Evergreen install for 
branding are just as valid a thing to track as the main code itself. By using 
the same tools that the developers are using you also get many of the same 
benefits the developers do. As the developers change things around your changes 
Git can, in many cases, re-apply your changes without having to ask you. Only 
when two different changes have touched the same lines will you have to figure 
things out for yourself.

As an added bonus, Git keeps older copies of changes as well, so you can go 
back to a previous version later, perhaps to see how something had been done 
previously, or because something broke and you need to go back to a known 
working version.

Git Basics
----------

Quick Git glossary
~~~~~~~~~~~~~~~~~~

Repository::
  A collection of files and changes to those files managed by Git.  Git is a 
distributed version control system, unlikely CVS or Subversion, and is designed 
to make it easy to copy a Git repository and push or pull changes between 
repositories.

Branch::
  A sequence of changes recorded in a Git repository.  A Git repository can 
have many branches, which can be used to organize lines of development and 
customization.  Managing a Git repository ultimately boils down to deciding 
when to create and merge branches.

Commit::
  A discrete set of changes to one or more files recorded in a Git repository.  
A commit also has a description, an author, and date attributes.

Patch::
  A Git commit expressed as a "diff" file.

Installing Git
~~~~~~~~~~~~~~

The first task in using Git to install Evergreen and manage customizations is 
to install Git itself. For this you should rely on your package manager, such 
as apt or yum, but take note that the package you want is likely named 
"git-core" instead of just "git".

.Installing Git examples
----
# Debian/Ubuntu
sudo apt-get install git-core
# Fedora/Red Hat
sudo yum install git-core
----

Once installed you should have access to the git command.

Configuring user information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Git stores author information with commits, but has horrible default settings. 
Thus it is highly recommended that you set your name and email address before 
committing anything with git.

You can set your name and email address for all repositories with two commands.

----
git config --global user.name "Firstname Lastname"
git config --global user.email "your_em...@youremail.com"
----

This is important because it indicates who made a change when multiple people 
work on things, and if you wish to share your work later you will want to make 
sure your name is on it.

Cloning a repository
~~~~~~~~~~~~~~~~~~~~

Next up is cloning the Evergreen repository. Git provides a clone function for 
this purpose that copies an entire remote repository to the local machine. 
While you can clone from any mirror you want, we recommend always cloning from 
the original (barring local mirrors thereof, of course).

----
# Clone the Evergreen repository
git clone git://git.evergreen-ils.org/Evergreen.git
----

This will create an "Evergreen" folder, in which you will find the "master" 
branch checked out.

Checking out branches
~~~~~~~~~~~~~~~~~~~~~

Assuming you are in a git directory (say, the Evergreen folder created by 
cloning above) you can "check out" new branches. These branches can be "local" 
or "remote", and you can create local branches from remote ones.

Checking out a local branch is as simple as using the checkout command on the 
local branch.

----
# Checkout a local branch
git checkout local_branch
----

To check a remote branch out as a local one you need to specify both the local 
name to use and the remote branch. This is also fairly easy, and only needs to 
be done once for each local branch you create.

----
# Create a local copy of a remote branch
# Note that this doesn't involve network traffic, and can be done offline
git checkout -b local_name remote_branch
----

NOTE: Technically, this runs "git branch" in the background before checking the 
resulting branch out. For more information see "git checkout --help" and "git 
branch --help".

Note that remote branches are named based on the remote's name and the branch 
name. By default the remote created by the clone command is "origin" and thus 
all remote branches will be named "origin/branchname".

As a shortcut, if you are checking out a remote branch from your origin remote 
and wish to use the same name you can use the first method of checking out. 
Thus, to check out the 2.2 working branch you would actually checkout 
origin/rel_2_2.

.Example checkouts
----
# Switch to local branch rel_2_2, or create from origin if non-existent
git checkout rel_2_2
# Create a copy of rel_2_2 named rel_2_2_local
git checkout -b rel_2_2_local origin/rel_2_2
# Switch to a previously created branch named local_customizations
git checkout local_customizations
----

Installing from a Git clone
---------------------------

For the most part installing from a Git clone of Evergreen or OpenSRF works the 
same way as installing from a tarball, just with a couple of extra steps tacked 
on.

First off you need to install and run the tools that build the configure 
script, and after running "make install" for the first time you need to install 
the dojo toolkit.

The best source of instructions for handling this is the README file itself, in 
the "Developer Instructions" section. By checking there you will be able to 
keep up with changes in dojo versions as well as additional needed packages.

The other potentially significant issue with installing from Git is 
translations, in that they are not built in the checked out branch. For a 
development system or one that only caters to en-US users this may not be a 
problem, but for everyone else building updated translations is important.

A more complete translation building document can be found at 
http://evergreen-ils.org/dokuwiki/doku.php?id=evergreen-admin:customizations:i18n[Internationalization
 (I18N), Localization (L10N), and Globalization (G11N)], but the basics are as 
follows. Note that you would ideally only do this just before installing.

----
# Install the translation build tools with your package manager. This only 
needs to be done once. On Debian/Ubuntu:
sudo apt-get install translate-toolkit python-dev python-levenshtein 
python-polib python-setuptools python-simplejson python-lxml
# Change to the build/i18n folder
cd build/i18n
# Build all locales
make install_all_locales
# Or, be picky (also useful when testing specific locales)
make newpot # install_all_locales does this automatically
make LOCALE=fr-CA install
----

Once that is completed the various translation files present in the tarball 
releases will be generated and ready to go, and should be copied into place as 
appropriate.

Adapting existing customizations to git
---------------------------------------

Once you can install from git you will want to get your existing customizations 
into it. If you don't have any yet then welcome to the community!

To start getting your customizations into git you should check out the release 
tag for the tarball you used. These will generally be in the form of 
"origin/tags/rel_?_?_?", for example "origin/tags/rel_2_1_0" for the original 
2.1 release. While you can simply use the rel_?_?_? branch name I recommend 
using something more distinctive. In fact, for reasons I will go into in a 
moment, I recommend having multiple branches.

Once you have the branch checked out you can simply copy your edited tarball 
files over the branch. Git will keep track of which files actually changed and 
which ended up identical. At this point you could store all of the resulting 
changes as one big commit, but that can be an unmaintainable mess. Instead I 
recommend splitting things up across commits, and even across branches.

Splitting things across well-named commits will make it easier to find changes 
later when looking to review them, makes those changes easier to remove if 
desired, and simplifies sharing those changes with the community if desired. In 
addition, when moving your changes to later versions of Evergreen you will be 
dealing with smaller chunks in the event something you changed conflicts with a 
change made in Evergreen.

Splitting commits across branches can keep changes grouped logically and 
simplifies having multiple people providing customizations down the road. For 
example, you may want to keep staff client changes separate from OPAC changes. 
If you have multiple skins for different library OPACs it is probably a good 
idea to keep them in a single branch each.

Luckily Git provides us with ways to take only certain changes when making 
commits.

Finding changed files
~~~~~~~~~~~~~~~~~~~~~

The first step in committing your changes is noting what files have been 
changed. Git provides us with the "git status" command, which shows us all 
modified files, as well as new files or folders. Modifications can be "staged" 
to be included in the next commit, or "unstaged" wherein they will not be added 
to the new commit. New, or "untracked," files and folders can be staged just 
like modified ones, however, and are treated as if the previous version was an 
empty file.

NOTE: The same file can be both "staged" and "unstaged" when some of the 
changes made to it are being committed and others are not.

Staging changes
~~~~~~~~~~~~~~~

You can see the full set of unstaged changes in a file with the "git diff" 
command. Without any arguments it will show you all unstaged changes (but not 
untracked files), with arguments you can limit it to specific files or folders.

If you want all of the changes in a specific file you can add it to the commit 
with the "git add" command. If you want to be more picky you can use the -p 
option to trigger interactive selection of changes to stage. This is useful 
when two somewhat unrelated changes have happened in the same file.

You can add as many changes as you want to a given commit.

NOTE: If you pass in a directory instead of a filename everything in the 
directory will be added, or prompted about with -p active.

Committing the changes
~~~~~~~~~~~~~~~~~~~~~~

Once you have staged your changes you need to commit them. This is accomplished 
with the "git commit" command. By default it will launch an editor to ask for a 
message, and I recommend ensuring that the message is descriptive of the intent 
of the change.

For example, if you are changing a color in a CSS file you could simply label 
the commit as "Change CSS file", but that won't tell you much later. Instead 
you should go with something more descriptive, taking advantage of the summary 
and full message. Note that the full message doesn't have to be very long.

.Example commit message
----
Change Default Background Color

Our logo doesn't work well on a white background, so change to a light grey.
----

In the example above the "Change Default Background Color" will show up in 
summary views of commits and gives a basic idea of what was being changed. The 
full message explains the reasoning behind the change, letting yourself and 
others know why the change was made later. Note that if the subject is longer 
than around 50 characters it may be truncated in some lists.

Oh, and just to be clear, the blank line is important as it splits the subject 
(the first line) from the rest of the commit message. This is thus a bad idea:

.Example bad commit message
----
Change Default Background Color
Our logo doesn't work well on a white background, so change to a light grey.
----

You can commit frequently as you stage files or combine larger groups of 
changes into single commits. A decent goal should be related changes all making 
it into the same commit, with minimal, if any, unrelated pieces in any given 
commit.

.Example Stage/Commit Command Set
----
# Find changed files
git status
# Check changed file
git diff Open-ILS/web/opac/skin/default/css/layout.css
# Stage all changes in that file
git add Open-ILS/web/opac/skin/default/css/layout.css
# Check second changed file
git diff Open-ILS/web/opac/skin/default/xml/footer.xml
# Only stage some changes
git add -p Open-ILS/web/opac/skin/default/xml/footer.xml
# Commit the staged changes
git commit
----

Switching branches
~~~~~~~~~~~~~~~~~~

Once you have collected all of the commits for a given broad topic, say OPAC 
customization, you may wish to switch branches to split off changes to other 
parts of the system. The most reliable way to accomplish this is to stash your 
current changes, checkout the new branch, and then pop the changes off of the 
stash.

.Changing branches for storing additional changes
----
# Stash the existing changes
git stash
# Checkout the new branch
git checkout -b staff_client_changes origin/tags/rel_2_1_0
# Pop the changes off of the stash
git stash pop
----

Once you have done this you can return to staging and committing changes.

Discarding changes
~~~~~~~~~~~~~~~~~~

In the event there are changes you no longer want, or are unrelated to your own 
work, you can discard them with the "git checkout" command, limited to a 
specific file. Just like the add command you can use -p to interactively choose 
changes to discard.

----
# Discard changes to file
git checkout Open-ILS/web/opac/skin/default/css/layout.css
# Selectively discard changes to file
git checkout -p Open-ILS/web/opac/skin/default/css/layout.css
----

NOTE: If you pass in a directory all changed files within it will have the 
changes within them discarded, or prompted about if you have -p active.

New Changes
-----------

Future changes you wish to make can be built on existing branches or in new 
ones. Simply edit files as desired, stage the changes, and commit them.

Installing Evergreen with your changes
--------------------------------------

Once you have your changes in place you will want to install them. For this 
purpose I recommend making an "install branch" that you have merged your 
changes into. This branch will consolidate your various change branches into a 
single complete whole from which you can perform your install.

Once you have created your branch you will want to merge each customization 
branch into place. This is accomplished with the "git merge" command. It merges 
whatever branch(es) you specify into the current one.

----
# Merge Client Customizations
git merge client_customizations
# And OPAC Customizations
git merge opac_customizations
# And two library skins at the same time
git merge library1_skin library2_skin
----

Upgrading Evergreen
-------------------

The real power in keeping your changes in git is being able to easily upgrade 
to later releases of Evergreen. Whether you are upgrading to the next security 
release or to another major version you can use git to get you there.

Either way, the first thing you want to do is update your copy of the server's 
repository. This can be done with the fetch command.

----
# The --all parameter says to update all remotes.
# You can specify just one instead of --all if you want.
git fetch --all
----

Minor upgrades
~~~~~~~~~~~~~~

When staying in the same major version you can use the "rebase" feature of git 
to re-apply your changes to the later code.

Unfortunately, moving from one tagged release to another means we will need to 
use an interactive rebase, so that we can remove the version numbering commit.

----
# Interactive Rebase
git rebase -i origin/tags/rel_2_1_1
----

One of the commits, hopefully the first one, will say something about version 
numbers, perhaps stating "Bumping version numbers" or similar. You will want to 
delete that line, then save and close the editor.

With any luck things will go smoothly and you will have had to do nothing 
special. If things don't go smoothly then git will stop where things have gone 
wrong so that you can fix them. At that point you would treat things like any 
other changes you have made, but resolving the conflicts between two sets of 
changes to the same areas. Also, instead of "git commit" you will want to use 
"git rebase --continue".

Once you have rebased all of your customization branches you can proceed to 
making your install branch and installing Evergreen.

Another tactic is to instead rebase your changes onto the in progress branch 
releases are built off of, say origin/rel_2_1. In that case you can usually 
merge without concern across updates until something conflicts or you want to 
be looking at more up to date code. Only then would you go back and rebase the 
branch again.

Major upgrades
~~~~~~~~~~~~~~

Major upgrades are a different matter. In this case you should build a new 
branch for each customization branch you have, say with the new version added 
to the end.

Once you have your new branch you will want to cherry-pick each commit from the 
old one onto the new one. To do that you will need the commit hashes for the 
commits you care about, and for that you can use git log.

----
# Show commits on a branch, summaries and hashes only
git log --pretty=oneline client_customizations
----

Once you have your list of commits you want to apply them from oldest to newest 
with git cherry-pick. If there are conflicts you would resolve them just as 
with a rebase, but in this case you return to using "git commit" when you are 
done staging the resolved conflicts.

----
# Cherry-pick - You can use a small piece of the front of the hash, or the 
entire thing
# And no, neither of these are likely hashes
git cherry-pick ffffffff
git cherry-pick eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
# In the event of a failure, go and correct things. Then commit it:
git commit
----

NOTE: A rebase is basically a more automated version of the cherry-pick steps 
just described.

Once you have your new branches you can then build a new install branch based 
on the new version.

Sharing with the community
--------------------------

Sometimes you have fixed a bug or built a new feature that you then want to 
share with the community. If you have been creating decent commit messages and 
keeping your changes split up fairly well then there are really only two more 
things to take into account when it comes to preparing your work, and then you 
have to actually share it.

Preparing a branch to share
~~~~~~~~~~~~~~~~~~~~~~~~~~~

The first is that you will need to sign-off on your changes, to indicate that 
you are permitted to submit the patch and is treated as signing the Developers 
Certificate of Origin (DCO).

The second is that you will want to split off your relevant commits into a 
branch of their own, so that only the changes you want to submit are in the 
branch.

Luckily, the process of building the branch provides us with a wonderful 
opportunity to apply the sign-off. As you cherry-pick the relevant commits into 
place on the new branch you can add the -s parameter to sign-off on the them 
automatically.

----
# Cherry-pick with sign-off
git cherry-pick -s ffffffff
git cherry-pick -s eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
----

In the event that you need to update the commit message on one of the commits, 
to add more detail or correct typos or such, you can also amend the commit 
afterwards to edit the commit message.

----
# Amend the commit, either to add more changes or to tweak the commit message
# To add more changes, stage them just like you would for a normal commit
git commit --amend
----

Sharing the work
~~~~~~~~~~~~~~~~

Once you have your branch you still need to make it visible to the world. I 
highly recommend reading the 
http://evergreen-ils.org/dokuwiki/doku.php?id=dev:git[Git] page on the 
dokuwiki, specifically the "Getting commit access to working repositories" and 
"Quick start for Evergreen contributors" sections. In general, however, your 
goal is basically:

. Find a public location to push to, such as the working repos. In the latter 
case, make sure you submitted your SSH key.
. Add the public location to your git checkout with the "git remote" command.
. Push your branch to the remote you are using.
. Publish the location of your branch, ideally via 
https://bugs.launchpad.net/evergreen[Launchpad].

Other uses of Git
-----------------

There are many other things you can use Git for. The key is to remember that 
Git helps track changes, and that any folder can be made into a Git repo simply 
by running "git init" while inside of it. Even those inside of other Git repos.

WARNING: The following line is likely groan-worthy. At least. You have been 
warned.

Yes, that means you can put Git in your Git so you can change while you change.

Potential other uses of Git include:

* Managing configuration files. By pushing changes into a Git branch you can 
track who changed what, push updates more easily across multiple servers, and 
make it easier to undo changes that turn out to be problematic.
* Swapping out files. By adding a Git repository to a folder on your web server 
you can swap out files quickly and easily by committing files to and checking 
out different branches. One such use I saw recently was to temporarily swap out 
CSS files for a weekend.
* Moving files around. With remotes you can use Git to move changes, on a push 
and a pull basis, across multiple machines. Regardless of what those changes 
are.
* Backing up files. Remote repositories can hold copies of your changes that 
you can easily get at later, though you should ensure any passwords are kept in 
private locations and for sanity reasons [red]*DO NOT BACK YOUR DATABASE UP 
WITH GIT*.

Going beyond Git 101
--------------------

Once you're comfortable using Git to manage your Evergreen customizations, 
there are a variety of additional resources available to make Git even more 
useful.

Repository management
~~~~~~~~~~~~~~~~~~~~

One of the things about Git repositories is that you are unlikely to have just 
one.  Over time, you're going to accrete a number of repositories, and it can 
be handy to have a tool to easily create repositories on a central server and 
grant access for users to pull or push from them.

Examples of Git repository mangement tools are:

. https://github.com/sitaramc/gitolite[Gitolite]
. https://wiki.archlinux.org/index.php/Gitosis[Gitosis]

Additional reading
~~~~~~~~~~~~~~~~~~

. http://book.git-scm.com[Git Community Book]
. http://progit.org/[Pro Git book by Scott Chacon]

Reply via email to