A Git Primer
cja@umich.edu
22 Jun 11
Verson 1.0


0 The Git Primer

This is a short introduction to the use of Git to manage your
development projects.  It is meant to get you up and running using
Git in a minimum of time.  It is not a comprehensive guide to all
of Git's features; for example, it does not discuss the index at
all.  For more extensive documentation, please see Section 1.3.

1 Installing Git

Currently, the multi-platform client software of choice is called
msysGit.  An excellent alternative for Windows users only (at time
of writing) is TortoiseGit.

1.1 Installing msysGit on Windows

Visit http://git-scm.com/download and select Windows inside the red
box.  On the "msysgit Git for Windows" download page that appears,
select the filename on the "full installer for official Git" line
(currently version 1.7.3.1).  On the next page, click on the filename
again to download it, then run the installer.  If you get a popup
warning about an unknown publisher, you can click "Run".  If you
get a User Account Control warning about an unidentified program
that wants access to your computer, you can click "Allow".  Then
follow the Git Setup Wizard, accepting all defaults, except on the
"Select Components" pane, check the "Git Bash Here" and "Git GUI
Here" components.

You can use either the Git command line interface or the fancy new
GUI.  For the former, go to All Programs, find the Git entry, and
click it; you'll see "Git Bash" and "Git GUI" underneath.  Clicking
"Git Bash" will start a BASH shell, mostly identical in behavior
to the BASH shell on UNIX and Linux.  "Git GUI" will start the Git
GUI.  The GUI invokes the Git command-line commands under the covers
while showing you graphically the state of your repository.

This primer genereally assumes you are using the Git comamnd line
interface.  When visualizing complex sequences of commits and merges,
however, the gitk GUI tool is very useful; please see Section 4.5.

1.2 Other operating systems

Visit http://git-scm.com/download and select your operating system
in the red box, and proceed as above.  For Linux (and other operating
systems that are not listed) you will be offered the msysGit source
code, which you can download and compile; see the instructions in
the INSTALL file in the top-level downloaded directory.

1.3 Installing TortoiseGit on Windows

Visit http://code.google.com/p/tortoisegit/ and select the Download
tab, then download the appropriate (32- or 64-bit) client.

TortoiseGit requires msysGit, so you should download and install
that product first, as described in earlier.

1.4 Documentation

Documentation is installed in the form of Linux manual pages for
all Git commands when you install msysGit.  If you want information
about git, type:

$ man git

If you want information about a git command, say "commit," type:

$ man git-commit

This documentation is quite complete, but does assume you understand
the Git framework.

You can also navigate to online help documentation using the Git GUI
by navigating to Help | Online Docoumentation.

There is also considerable information on the web, for example:

A good online tutorial:
http://www.kernel.org/pub/software/scm/git/docs/gittutorial.html

Another tutorial, which I have not used:
http://gitref.org/

For folks used to SVN, a "crash course" in converting to Git:
http://git-scm.com/course/svn.html

A "crib sheet" of common Git commands, grouped by role (developer,
integrator, etc.), including per-user shared repository authorization:
http://www.kernel.org/pub/software/scm/git/docs/everyday.html

Finally, the O'Reilly book by John Loeliger, "Version Control with
Git," is quite thorough and well-written.


2 Working with development repositories

Every developer creates an instance of a Git repository in his or
her own code development directory, updating the repository contents
when appropriate by issuing commits.  You can have multiple Git
repositories.

2.1 Create a repository

2.1.1 Populate your development directory

You populate your development directory in the usual manner, say, by
using tar to unpack an existing code archive.  In this example I have
an existing tarball that creates files in a new directory src:

$ tar zxf src.tgz
$ cd src
$ ls
.               chkcrlf.c       hello.c         reverse.c       trcsg.c
..              count.c         hn.c            ssq.c           untrcsg.c
ascii.c         countnonasc.c   home.c          ssq2.c          usleep.c
att.c           crush.c         ll.c            stack.c         ut.c
attv.c          csv.c           loop.c          tbd.c           vtp.c
attw.c          ctp.c           pghack.c        tde.c           xkey.c
bold.c          dosify.c        pghack2.c       thr.c
calen.c         fixfls.c        pghack3.c       ticker.c
cctime.c        fpri.c          pghack4.c       titleb.c
chad.c          gib.c           pi.c            tr2htmlcsg.c

2.1.2 Create a repository

Create a repository for this working directory:

$ git init
Initialized empty Git repository in /Users/cja/src/

$ ls
.               chad.c          gib.c           pi.c            tr2htmlcsg.c
..              chkcrlf.c       hello.c         reverse.c       trcsg.c
.git            count.c         hn.c            ssq.c           untrcsg.c
ascii.c         countnonasc.c   home.c          ssq2.c          usleep.c
att.c           crush.c         ll.c            stack.c         ut.c
attv.c          csv.c           loop.c          tbd.c           vtp.c
attw.c          ctp.c           pghack.c        tde.c           xkey.c
bold.c          dosify.c        pghack2.c       thr.c
calen.c         fixfls.c        pghack3.c       ticker.c
cctime.c        fpri.c          pghack4.c       titleb.c

Git has created a directory .git, in which it keeps all of its metadata,
while it leaves your other files alone.

2.1.3 Establish your identity

In Git, all changes you make are identified with your user name and
email address.  Git tries to determine them automatically, but they
will usually be wrong on Windows systems.  Specify them yourself:

git config user.name "John Q Public"
git config user.email "jqp@example.com"

Of course, use your own values.  If you get "git: command not found,"
now would be a good time to install Git as described in Section 1 :-).

If you forget this step, don't worry.  You can correct these values
after your first commit, as shown below.


2.2 Populate your repository

"Git init" creates an empty repository.  You have to put the initial versions
of your files into it, first by adding all the files to a "staging area,"
and then by committing the files from the staging area into the repository.
This two-step process is quite powerful, but you can ignore the staging area
for now.

2.2.1 Stage the files:

$ git add .

Here "." means the current directory, so all files in the src directory are
added.

If you want to see what has been done, type

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   ascii.c
#       new file:   att.c
#       new file:   attv.c
#       new file:   attw.c
#       new file:   bold.c
#       new file:   calen.c
#       new file:   cctime.c
#       new file:   chad.c
#       new file:   chkcrlf.c
#       new file:   count.c
#       new file:   countnonasc.c
#       new file:   crush.c
#       new file:   csv.c
#       new file:   ctp.c
#       new file:   dosify.c
#       new file:   fixfls.c
#       new file:   fpri.c
#       new file:   gib.c
#       new file:   hello.c
#       new file:   hn.c
#       new file:   home.c
#       new file:   ll.c
#       new file:   loop.c
#       new file:   pghack.c
#       new file:   pghack2.c
#       new file:   pghack3.c
#       new file:   pghack4.c
#       new file:   pi.c
#       new file:   reverse.c
#       new file:   ssq.c
#       new file:   ssq2.c
#       new file:   stack.c
#       new file:   tbd.c
#       new file:   tde.c
#       new file:   thr.c
#       new file:   ticker.c
#       new file:   titleb.c
#       new file:   tr2htmlcsg.c
#       new file:   trcsg.c
#       new file:   untrcsg.c
#       new file:   usleep.c
#       new file:   ut.c
#       new file:   vtp.c
#       new file:   xkey.c
#

This shows all the files that will be put in your repository, as
well as giving you a command you can type if you want to undo your
add step entirely.

2.2.2 Commit the staged files

Type "git commit" to commit your staged files to the repository.
You will be placed into an editor positioned at the top of a file
that looks very much like it was generated by the "git status"
command above.  By convention, you should enter a one-line summary
of changes here, and then a blank line and a more detailed description
if necessary.  As this is the initial commit, it is sufficent to
enter something like "Initial commit.", then save and exit from the
editor.

Alternatively, for short descriptions, you can append the summary
directly to the git commit command, and you won't be put in an
editor:

$ git commit -m 'Initial commit.'
[master (root-commit) 82ba5c4] Initial commit.
 Committer: Charles Antonelli <cja@smartstructure.engin.umich.edu>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

If the identity used for this commit is wrong, you can fix it with:

    git commit --amend --author='Your Name <you@example.com>'

 44 files changed, 3547 insertions(+), 0 deletions(-)
 create mode 100644 ascii.c
 create mode 100644 att.c
 create mode 100644 attv.c
 create mode 100644 attw.c
 create mode 100644 bold.c
 create mode 100644 calen.c
 create mode 100644 cctime.c
 create mode 100644 chad.c
 create mode 100644 chkcrlf.c
 create mode 100644 count.c
 create mode 100644 countnonasc.c
 create mode 100644 crush.c
 create mode 100644 csv.c
 create mode 100644 ctp.c
 create mode 100644 dosify.c
 create mode 100644 fixfls.c
 create mode 100644 fpri.c
 create mode 100644 gib.c
 create mode 100644 hello.c
 create mode 100644 hn.c
 create mode 100644 home.c
 create mode 100644 ll.c
 create mode 100644 loop.c
 create mode 100644 pghack.c
 create mode 100644 pghack2.c
 create mode 100644 pghack3.c
 create mode 100644 pghack4.c
 create mode 100644 pi.c
 create mode 100644 reverse.c
 create mode 100644 ssq.c
 create mode 100644 ssq2.c
 create mode 100644 stack.c
 create mode 100644 tbd.c
 create mode 100644 tde.c
 create mode 100644 thr.c
 create mode 100644 ticker.c
 create mode 100644 titleb.c
 create mode 100644 tr2htmlcsg.c
 create mode 100644 trcsg.c
 create mode 100644 untrcsg.c
 create mode 100644 usleep.c
 create mode 100644 ut.c
 create mode 100644 vtp.c
 create mode 100644 xkey.c

This shows that 44 files jointly containing 3547 lines that have been
committed to your repository, as well as some instructions at the top
for fixing your name and email address if that is needed.

You can use "git log" to see what has been done:

$ git log
commit 82ba5c4fc42c937c3b8e2b0ebc5813d5bc5d7c80
Author: Charles Antonelli <cja@smartstructure.engin.umich.edu>
Date:   Fri Oct 15 11:50:35 2010 -0400

    Initial commit.

That long number 82ba5c4fc42c937c3b8e2b0ebc5813d5bc5d7c80 is a hash, and
is used by Git to figure out if two files (or directories, or entire
respositories) contain identical contents.  You sometimes have to
type in these hashes, although Git mostly tries to avoid this.

2.3 Working in your development directory

2.3.1 Committing changes

You can edit files in your development directory, compile, test, and so
forth, as usual.  When you have a set of changed files you would like
to commit to the repository, type, say:

$ git add csv.c
$ git commit -m 'Added note on reuse.'
[master 5864bf8] Added note on reuse.
 Committer: Charles Antonelli <cja@smartstructure.engin.umich.edu>
 1 files changed, 2 insertions(+), 0 deletions(-)

You can have multiple files on the git add command, to commit related
changes together.

Now git log shows:

$ git log
commit 5864bf89e42ea0378fba11246cc121030ef76b9f
Author: Charles Antonelli <cja@smartstructure.engin.umich.edu>
Date:   Fri Oct 15 12:17:57 2010 -0400

    Added reuse heading.

commit 82ba5c4fc42c937c3b8e2b0ebc5813d5bc5d7c80
Author: Charles Antonelli <cja@smartstructure.engin.umich.edu>
Date:   Fri Oct 15 11:50:35 2010 -0400

    Initial commit.

To see a diff of the changes, type:

$ git show
commit 5864bf89e42ea0378fba11246cc121030ef76b9f
Author: Charles Antonelli <cja@smartstructure.engin.umich.edu>
Date:   Fri Oct 15 12:17:57 2010 -0400

    Added reuse heading.

diff --git a/csv.c b/csv.c
index e59bd0f..7b0eacc 100644
--- a/csv.c
+++ b/csv.c
@@ -1,3 +1,5 @@
+// this is a classic example of code re-use
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

This shows that the change consisted of adding two lines at the top of the file.

You can also give a commit number:

$ git show 82ba5c4fc42c937c3b8e2b0ebc5813d5bc5d7c80

As this is the commit number of the initial commit, this command will
list every line of every file added in the initial commit.

2.3.2 Undoing a commit

If you want to undo the most recent commit, while leaving the changes you
made to the files in your working tree, enter:

$ git reset --soft HEAD^
$ git log
commit 82ba5c4fc42c937c3b8e2b0ebc5813d5bc5d7c80
Author: Charles Antonelli <cja@smartstructure.engin.umich.edu>
Date:   Fri Oct 15 11:50:35 2010 -0400

    Initial commit.

The commit has disappeared.

NOTE:  the file remains as you changed it in your working directory;
only the repository copy has been reverted to the previous version.
To revert the working directory version as well, type instead:

$ git reset --hard HEAD^

Be careful with --hard:  it will wipe out all of your uncommitted work
in your working directory; be very sure that is what you want.

2.3.3  Adding files

You can add a new file by:

$ vi new.c
$ git add new.c
$ git commit -m 'Collected transport functions.'

You can also create new directories and subdirectories to put new files
into.  Git handles this automatically.

2.3.4  Removing files

You can remove a file by:

$ git rm new.c
$ git commit -m 'Didn't want this after all.'

2.3.5  Renaming files

You can rename a file by:

$ git mv new.c bang.c
$ git commit -m 'Wanted a more onomatopoetic name.'

2.3.5 Retrieving a committed file

Sometimes it is useful to restore a single file or set of files
from a given commit.  You can do this by, e.g.,

$ git checkout 82ba5c4fc42c937c3b8e2b0ebc5813d5bc5d7c80 tde.c ctp.c

This restores the contents of the files tde.c and ctp.c from the
commit identified by the hash 82ba5c4fc42c937c3b8e2b0ebc5813d5bc5d7c80
to your working directory, overwriting any version of those files
already there.


3 Working with depots

"Depot" is Git-speak for an authoritative master repository.  It is
a "bare" repository, Git-speak for a repository that is not intended
to be used directly by developers --its only purpose is to serve as
the authoritative repository from which developers will pull code
into their own repositories, and push code or patches back into for
others to use.

3.1 Create a depot

A depot is usually created by copying a regular development repository's
contents into it.  This is called "cloning."  By convention, a bare
repository is given a ".git" extension:

$ cd ~
$ mkdir depot
$ cd depot
$ git clone --bare ~/src src.git
Cloning into bare repository src.git...
done.
$ cd src.git
$ ls
.               branches        hooks           packed-refs
..              config          info            refs
HEAD            description     objects

This clones the development directory ~/src into bare (depot)
directory ~/depot/src.git.  Note that some Git metadata has been
created in the depot directory, but no files appear there.  The
files have been copied into the depot repository, however.

3.2  Clone from the depot

Here's how to create a clone of a depot repository on any machine
on which git is installed.  You need to know the hostname on which
the depot is stored (here "smartstructure.engin.umich.edu") and the
pathname from the root of the host's filesystem to where the depot
is stored (here "/Users/cja/depot/src"):

$ cd ~
$ mkdir gitwork
$ cd gitwork
$ git clone ssh://smartstructure.engin.umich.edu/Users/cja/depot/src
Cloning into src...
Password:
remote: Counting objects: 61, done.
remote: Compressing objects: 100% (54/54), done.
remote: Total 61 (delta 12), reused 0 (delta 0)
Receiving objects: 100% (61/61), 28.75 KiB, done.
Resolving deltas: 100% (12/12), done.

This creates a clone of the depot repository in ~/gitwork:

$ ls
.       ..      src
$ ls src
.               chad.c          gib.c           pghack4.c       titleb.c
..              chkcrlf.c       hello.c         pi.c            tr2htmlcsg.c
.git            count.c         hn.c            reverse.c       trcsg.c
ascii.c         countnonasc.c   home.c          ssq.c           untrcsg.c
att.c           crush.c         ll.c            ssq2.c          usleep.c
attv.c          csv.c           loop.c          stack.c         ut.c
attw.c          ctp.c           new.c           tbd.c           vtp.c
bold.c          dosify.c        pghack.c        tde.c           xkey.c
calen.c         fixfls.c        pghack2.c       thr.c
cctime.c        fpri.c          pghack3.c       ticker.c

3.3 Working in the clone repository

You can work in the clone repository in the usual way, e.g., using
'git add' and 'git commit' to make changes.

There are two common scenarios you will need to keep track of if
multiple develoeprs are working in the same repository.

3.3.1 Updating your repository with others' changes

In order to update your clone from the depot, to pick up changes that
other developers are making, you should:

$ git pull

This will copy any changes from the depot to your local repository.  Other
files in your repository and working directory will be left alone.

NOTE:  If other developers have made changes that conflict with
changes you have made to your local repository, the pull operation
will create in your local repository a merged copy of each file in
which conflicts exist, with all sets of conflicting changes annotated
in each file.  Here's how conflicts are annotated:

[...]
<<<<<<< HEAD
        foo
=======
	bar
	baz
>>>>>>> 5a20364e41efd51756b837d4e898b890cd2fd87c
[...]

(Here one version of a file contains the line "foo'" in the same
place where the other version contains the lines "bar" and "baz".)
You will then have to edit each file to resolve the conflicts, and
then push the changes back to the depot [1].

3.3.2  Updating the depot with your changes

In order to update the depot from your clone, to let other developers
see your changes, you should:

$ git push

This will copy your changes to the depot.

NOTE:  If other developers have made changes that conflict with changes
you have made to your local repository, the push operation will fail.
You should perform a git pull operation and merge all changes in your
local repository, as described in Section 3.3.1, before attempting
another git push.


4 Working with branches

Branches in Git allow you to start a separate line of development
from an arbitrary commit in a repository.  Development activity and
commit operations proceed entirely independently in each branch.
A branch can later be merged with another branch, perhaps the branch
it was started from, or it can continue independently of any other
branch.

When you create a new repository, a default branch named "master"
is created for it.  We have been implictly using the master branch
in the preceding material.

4.1 Preliminaries

Let's create another local copy of the source repository:

$ cd ~
$ mkdir gitwork2
$ cd gitwork2
$ git clone ssh://smartstructure.engin.umich.edu/Users/cja/depot/src
Cloning into src...
$ cd src

$ git branch
* master

The git branch command lists all the branches in your repository, with
a * next to the current one.  Right now we have only the master, and it
is the current branch.

$ git log --pretty=oneline       
265c0045eec3912806575d788d4013abad9b39be Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
2ca1a6438eacca319507a15b8b56b0f41d0eab83 second version
5a20364e41efd51756b837d4e898b890cd2fd87c a newer file.
b0f61391b1abb4bbbf5a42dd7bcdb651bec333b8 Merge branch 'master' of ssh://smartstructure/Users/cja/depot/src
b226db6bcb125409d05cad6f0359a07ebac2a853 change 2 from cee-moritz
efcd88f5a1602665acc6b6a29093d5f157ddfc01 change 1 from css-max
6c16902e0a22941f8fdedb4e6b5bbb2b6da640dd done on cee-moritz
59334080d2ab7f1fc1a004785f907d1435db71fb a new file
af4b6b682b7153b823644b00f20e137c38314e6f Initial commit.

Here the "--pretty=oneline" restricts each commit to a single line.
The hexadecimal numbers are the ID's of the commits that have been done
on the master branch.  The tip of the current branch is always labeled
HEAD, e.g.

$ git log -1 pretty=oneline HEAD
265c0045eec3912806575d788d4013abad9b39be Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)

This shows the most recent commit at the end of the current branch.  The
"-1" argument means show only that one commit.

$ git log --pretty=oneline HEAD~1..HEAD
265c0045eec3912806575d788d4013abad9b39be Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
5a20364e41efd51756b837d4e898b890cd2fd87c a newer file.

This shows the most recent commit (named HEAD~1) and the most recent
commit.  Conventionally, Git counts commits backwards from the HEAD
using the "HEAD~n" notation.  There is no way to reference the first
commit of a branch directly.  You can assign an arbitrary name to a
commit by tagging it:

$ git tag -m"Base version 1.0" V1.0 6c16902e0a22941f8fdedb4e6b5bbb2b6da640dd

Now you can refer to that commit using the tag:

$ git log --pretty=oneline V1.0

0a22941f8fdedb4e6b5bbb2b6da640dd done on cee-moritz
59334080d2ab7f1fc1a004785f907d1435db71fb a new file
af4b6b682b7153b823644b00f20e137c38314e6f Initial commit.

This shows the "done on cee-moritz" commit.  As "-1" was not specified,
if shows all older commits as well.

4.2 Creating a branch

To create a new branch, type:

$ git branch mynewbranch V1.0
$ git branch
* master
  mynewbranch

So we have a new branch, but master is still the current branch.

NOTE:  branch names can be hierarchically structured, e.g. new/foo,
new/foo2, new/bar, etc.  This allows wildcards to be used when
referencing multiple branches, e.g. new/f* gets all the foos.

To see the branch structure, use show-branch:

$ git show-branch
* [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
 ! [mynewbranch] done on cee-moritz
--
-  [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
*  [master^2] a newer file.
*  [master^] second version
*  [master~2^2] change 1 from css-max
*  [master~3] change 2 from cee-moritz
*+ [mynewbranch] done on cee-moritz

The two lines above the "--" show the two branches in the repository
(master and mynewbranch) along with the last commit on each.  A *
here means this is the head of the current branch (as master is the
current branch) and a ! means it is the head of some other branch
(as mynewbranch is not the current branch).  The branches thus form
two columns each headed by their ! or * character.

The lines below the "--" show commits on the two branches; a + in the
a column indicates that that branch contains this commit, and a blank
indicates it does not.  A merge commit is shown with a -; a commit on
the current branch is shown with a *.  So "done on cee-moritz" is
present in both branches, which the master branch contains a lot of
other commits [2].

4.3 Working in a branch

We can switch the current branch to the root:

$ git checkout mynewbranch
Switched to branch 'mynewbranch'
$ git branch
  master
* mynewbranch

Showing the branch contents again:

$ git show-branch
! [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
 * [mynewbranch] done on cee-moritz
--
-  [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
+  [master^2] a newer file.
+  [master^] second version
+  [master~2^2] change 1 from css-max
+  [master~3] change 2 from cee-moritz
+* [mynewbranch] done on cee-moritz

We see that our new branch is current, and the only commit on it is
"done on cee-moritz".

We can work on this branch in the usual manner:

$ vi stack.c

When ready to commit:

$ git add stack.c
git commit
[mynewbranch 662c57c] Added a header comment.
 1 files changed, 2 insertions(+), 0 deletions(-)

Showing the branch contents shows the new commit on mynewbranch:

$ git show-branch
! [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
 * [mynewbranch] Added a header comment.
--
 * [mynewbranch] Added a header comment.
-  [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
+  [master^2] a newer file.
+  [master^] second version
+  [master~2^2] change 1 from css-max
+  [master~3] change 2 from cee-moritz
+* [mynewbranch^] done on cee-moritz

Let's make another modification:

$ vi loop.c
$ git commit -a -m'Added another useful comment.'
[mynewbranch f83da24] Added another useful comment.
 1 files changed, 1 insertions(+), 0 deletions(-)
$ git show-branch
! [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
 * [mynewbranch] Added another useful comment.
--
 * [mynewbranch] Added another useful comment.
 * [mynewbranch^] Added a header comment.
-  [master] Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
+  [master^2] a newer file.
+  [master^] second version
+  [master~2^2] change 1 from css-max
+  [master~3] change 2 from cee-moritz
+* [mynewbranch~2] done on cee-moritz

Here the "-a" option to commit tells Git to commit all files in the
working directory that are different with respect to the repository
versions.  In other words, it combines the staging and commit steps.

4.4 Merging a branch

At some point we might wish to merge a branch with another.  This
is done by checking out the target branch and then merging the other
branch into it.  For example, if you wish to merge mynewbranch back
into the master branch:

$ git checkout master
Switched to branch 'master'
$ git merge mynewbranch
Merge made by recursive.
 loop.c  |    1 +
 stack.c |    2 ++
 2 files changed, 3 insertions(+), 0 deletions(-)

Looking at the new branch structure:

$ git show-branch
* [master] Merge branch 'mynewbranch'
 ! [mynewbranch] Added another useful comment.
--
-  [master] Merge branch 'mynewbranch'
*+ [mynewbranch] Added another useful comment.

What happened to the rest of the structure?  By default, Git only
shows branch commits back to the nearest common commit.  (After the
merge, this latest commit is in both branches.)  If we want to see
it all, specify a count:

$ git show-branch --more=10
* [master] Merge branch 'mynewbranch'
 ! [mynewbranch] Added another useful comment.
--
-  [master] Merge branch 'mynewbranch'
*+ [mynewbranch] Added another useful comment.
*+ [mynewbranch^] Added a header comment.
*  [master^^2] a newer file.
*  [master~2] second version
*  [master~3^2] change 1 from css-max
*  [master~4] change 2 from cee-moritz
*+ [master~5] done on cee-moritz
*+ [master~6] a new file
*+ [master~7] Initial commit.

4.5 Viewing the commit graph

The commit graph is a bit difficult to visualize using show-branch.
The git log command can show a bit of ascii art:

$ git log --graph --pretty=oneline --abbrev-commit
*   6f0d07e Merge branch 'mynewbranch'
|\  
| * f83da24 Added another useful comment.
| * 33c1a9f Added a header comment.
* |   265c004 Merge branch 'master' of /Users/cja/devel2/../depot/src (had to manually patch newer.c to resolve conflicts within it)
|\ \  
| * | 5a20364 a newer file.
* | | 2ca1a64 second version
|/ /  
* |   b0f6139 Merge branch 'master' of ssh://smartstructure/Users/cja/depot/src
|\ \  
| * | efcd88f change 1 from css-max
| |/  
* | b226db6 change 2 from cee-moritz
|/  
* 6c16902 done on cee-moritz
* 5933408 a new file
* af4b6b6 Initial commit.

(Here "--abbrev-commit" shows only enough of those long hexadecimcal
IDs so that every abbreviated ID is unique.)  The latest commit,
i.e. the merged branch) is at the top, with the master branch on
the left and mynewbranch on the right.

When installing msysGit a GUI tool called gitk is also installed.  This
tool is very useful for showing the above diagram in a more readily
understandable way.  You can also easily show differences between any two
commits.  You invoke it as follows:

$ cd /my/local/repository
$ gitk

Using gitk, it is easier to see that the mynewbranch branch sprouted
from the "done on cee-moritz" branch and added the two "header
comment" commits, before merging back with the master.  The other
complexity on the master is shown to be two separate instances where
incompatible changes were made to the same file, which was immediately
resolved in each case.

4.6 Pushing back to the depot

After creating, working with, and merging the branch, we can push
the repository back to the depot:

$ git push
Password:
Counting objects: 12, done.
Delta compression using up to 16 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (8/8), 865 bytes, done.
Total 8 (delta 4), reused 0 (delta 0)
To ssh://smartstructure.engin.umich.edu/Users/cja/depot/src
   265c004..6f0d07e  master -> master

Now the depot contains the new branch.  Another developer can pull
the updates from the depot including the new branch into his or her
local repository in the usual way:

$ cd mygit2
$ git pull
remote: Counting objects: 12, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 8 (delta 4), reused 0 (delta 0)
Unpacking objects: 100% (8/8), done.
From /Users/cja/devel2/../depot/src
   265c004..6f0d07e  master     -> origin/master
Updating 265c004..6f0d07e
Fast-forward
 loop.c  |    1 +
 stack.c |    2 ++
 2 files changed, 3 insertions(+), 0 deletions(-)

$ git log --graph --pretty=oneline --abbrev-commit

 git log --graph --pretty=oneline --abbrev-commit
*   6f0d07e Merge branch 'mynewbranch'
|\  
| * f83da24 Added another useful comment.
| * 33c1a9f Added a header comment.
* |   265c004 Merge branch 'master' of /Users/cja/devel2/../depot/src (had to ma
|\ \  
| * | 5a20364 a newer file.
* | | 2ca1a64 second version
|/ /  
* |   b0f6139 Merge branch 'master' of ssh://smartstructure/Users/cja/depot/src
|\ \  
| * | efcd88f change 1 from css-max
| |/  
* | b226db6 change 2 from cee-moritz
|/  
* 6c16902 done on cee-moritz
* 5933408 a new file
* af4b6b6 Initial commit.


Footnotes
 
[1]  Of course, the second push will fail if someone else has pushed
     conflicting changes to the repository after you performed the
     pull.  In this case, simply merge and push again.  This is
     okay, and doesn't happen often.

[2]  Given a commit named C in a commit graph G, C~1 is the first
     parent of C, C~2 the first grandparent, C^1 is the first parent,
     and c^2 is the second parent, and so on.  These may be combined
     to address any node in G, e.g. master~2^2 means the second
     parent of the graph rooted at the master's HEAD.  (In Git, the
     root of the graph is at the bottom, and subordinate nodes are
     labeled as parents.)