Git

overview ...

Git is a distributed version control system that gives each developer a local copy of the full development history. The local copy is not a working copy, it is a full replication.

Git repositories can be local or server based. Changes are imported as added development branches that can be merged with the main line development branch.

For the most part, code management is handled the same on locally based and server based systems.

Git's native environment is in the terminal. That is the environment used throughout this site. There are several gui based tools available that can be considered after you understand the git basics. You can find out more here.

All examples on this site use the command line and have been tested under Linux. For Windows installations, run the git-bash.exe program to run the git shell command line tool. This tool is available from the Windows default installation.

differences between git and svn

SVN is server based. The master copy of the repository is stored on a centralized machine. When you checkin or commit your changes, the server is updated. Merge conflicts are often avoided by using "checkout-lock" operations.

Git is a distributed revision control system. All developers have a full copy of the repository. There is a server component, but it is not required. Git does not have the concept of a "locked" file.

Some terms mean very different things between SVN and git. A few of the most commonly used terms are discussed below.

command/operation svn meaning git meaning
commit post changes to the server repositor post changes to local branch
checkout get a local copy of the code change branch
synchronize local copy update pull/fetch

Git encourages branching and merging. Both should be a part of your daily routine.

getting started ...

First, setup the global configuration for your machine. Global settings identify you throughout the system. The following commands update the file ~/.gitconfig (on Windows the file might be in the $HOME directory).

The following examples demonstrate how to initialize both a local project and one from a remote server. It also shows how to add a file to the repository. The text in white is the response that you should expect to see as you execute each command.

example Initializing a Repository in an Existing Directory

Create the directory "repository" in your home directory before you execute the following steps.

  
cd ~/repository
git init project1 
Initialized empty Git repository in /home/hagartyd/repository/project1/.git/

cd project1
git status 
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

touch myfile.txt (creates the file myfile.txt)
git status 
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

  myfile.txt

nothing added to commit but untracked files present (use "git add" to track)

git add myfile.txt
git status 
    On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

  new file:   myfile.txt
      
git commit -m "Added myfile.txt" 
[master (root-commit) ea3a039] Added myfile.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 myfile.txt
  
git status 
On branch master
nothing to commit, working tree clean
  
  

At this point, you have created a repository project and added a file so that it's history can be tracked...

gedit myfile.txt (make some changes and save the file) git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: myfile.txt no changes added to commit (use "git add" and/or "git commit -a") git commit -a -m "Modified myfile.txt" [master 5228cbd] Modified myfile.txt 1 file changed, 1 insertion(+)

... and now you have modified a file and built a history of revisions.

example Cloning an Existing Repository
cd ~/repository
git clone https://github.com/libgit2/libgit2
  Cloning into 'libgit2'...
remote: Counting objects: 74995, done.
remote: Compressing objects: 100% (21422/21422), done.
remote: Total 74995 (delta 52275), reused 74898 (delta 52182), pack-reused 0
Receiving objects: 100% (74995/74995), 35.09 MiB | 430.00 KiB/s, done.
Resolving deltas: 100% (52275/52275), done.
cd libgit2
git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

If you look at the directory libgit2, you'll notice that you downloaded a number of files. At this point, you have a full copy of the project that you can work on.

As you work through the examples, you should get a sense of the git workflow (see below).

Files that are in a git working directory are either "tracked" or "untracked". Tracked files can be unmodified, modified or staged. Untracked files are everything else.

Each commit creates a snapshot. A file cannot be committed until it is staged. Only tracked files can be staged. To stage a file use git add filespec.

Git lifecycle
managing change

As you work through a project, the state of your files will change on a regular basis.

The git status command provides a quick glimpse at the state of your repository.

The git diff command provides more detail regarding the changes that where made to individual files.

The git diff command (no arguments) will show you what you've changed, but not yet staged.

The git diff --staged command will show you what you've staged. These changes will go in with your next commit.

example Using git diff to view changes
vi README
git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

  README

nothing added to commit but untracked files present (use "git add" to track)


git add README
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  new file:   README


git commit -m "Added README"
[master c501461] Added README
 1 file changed, 2 insertions(+)
 create mode 100644 README


git status
On branch master
nothing to commit, working tree clean


vi README
git diff
diff --git a/README b/README
index b9722a4..7608d63 100644
--- a/README
+++ b/README
@@ -1,2 +1,2 @@
 First entry.
-
+Second entry.


git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

  modified:   README

no changes added to commit (use "git add" and/or "git commit -a")


git add README
git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

  modified:   README


git diff
git diff --staged
diff --git a/README b/README
index b9722a4..7608d63 100644
--- a/README
+++ b/README
@@ -1,2 +1,2 @@
 First entry.
-
+Second entry.


git commit -m "Second entry in README"
[master fbcdd7d] Second entry in README
 1 file changed, 1 insertion(+), 1 deletion(-)
git status
On branch master
nothing to commit, working tree clean


Use the git log command to view the commit history.

git commit --amend will add staged items to the last commit. This is handy if you did a commit and forgot to add some files.

Use the git reset HEAD filespec command to "unstage" filespec

The git checkout -- filespec will undo changes to filespec if

remote repositories

Collaboration is accomplished by git via remote repositories. Remote repositories are versions of your project that are hosted on a computer that team members can access either over a LAN or the Internet. You will push or pull data to these repositories when you need to share files.

To make a copy of a remote repository: git clone URL where, URL is the location of the repository.

Git URLs can use one of these protocols

git remote [-v] will list all of your remote repositories.

example show remote repositories
git clone https://github.com/libgit2/libgit2
Cloning into 'libgit2'...
remote: Counting objects: 75002, done.
remote: Compressing objects: 100% (21398/21398), done.
remote: Total 75002 (delta 52213), reused 75001 (delta 52213), pack-reused 0
Receiving objects: 100% (75002/75002), 35.22 MiB | 428.00 KiB/s, done.
Resolving deltas: 100% (52213/52213), done.


cd libgit2/
git remote -v
origin	https://github.com/libgit2/libgit2 (fetch)
origin	https://github.com/libgit2/libgit2 (push)

Use the git fetch branch name to retrieve updates from the remote repository. When you clone a repository branch name is called origin. Knowing that, then git fetch origin fetches any new work that has been posted to the remote location.

fetch does not do a merge

The git pull command generally fetches data from the cloned serverand automatically tries to merge it with your locally stored code.

Use the git push origin master to post your changes to the server.

git remote show origin provides a full listing, including the names of all branches, from the remote location.

the git branching model

In git, a branch indicates an independent line of development.

Branching allows you to diverge from the main line of development and continue to do work. The git merge command is used to move your work back into the main line. Git encourages workflows that branch and merge often.

Git stores data as a series of snapshots. A commit operation creates a snapshot. A branch in git is simply a movable pointer to one of the commits (snapshot). A branch also knows about the the commit that came before it.

When you first create a repository and commit changes, git creates the default branch named master. git branch will display all of your branch names. git branch newBranchName creates a new branch that points to the commit that you're currently on. It does not switch to that branch, use git checkout -b if you want to do that.

The git merge command is used to synchronize branches.

HEAD is a special pointer that points to the local branch that you are currently on.

git log shows you where the branch pointers are pointing.

To switch branches, run the git checkout branchName command. That command moves HEAD to the branchName branch.

example show how the branch pointer moves between commits
git init project4
  Initialized empty Git repository in /home/hagartyd/repository/project4/.git/
cd project4
touch file1
git add file1
git commit -m "first commit"
 [master (root-commit) 4675f58] first commit
  1 file changed, 0 insertions(+), 0 deletions(-)
  create mode 100644 file1
git branch
  * master
git log
commit COMMIT_#1 (HEAD -> master)
git checkout -b branch1
  Switched to a new branch 'branch1'
vim file1
git commit -a -m "Commit from branch1"
  [branch1 8965f99] Commit from branch1
   1 file changed, 1 insertion(+)
git log
  commit COMMIT_#2 (HEAD -> branch1)
  Author: Dan Hagarty <dan.hagarty.ctr@navy.mil>
  Date:   Thu Jun 1 07:10:04 2017 -0400

      Commit from branch1

  commit COMMIT_#1 (master)
  Author: Dan Hagarty <dan.hagarty.ctr@navy.mil>
  Date:   Thu Jun 1 07:09:17 2017 -0400

      first commit
      
git checkout master
  Switched to branch 'master'
git merge branch1
  Updating 4675f58..8965f99
  Fast-forward
   file1 | 1 +
   1 file changed, 1 insertion(+)
git log
  commit COMMIT_#2(HEAD ->master, branch1 )
  Author: Dan Hagarty <dan.hagarty.ctr@navy.mil>
  Date:   Thu Jun 1 07:10:04 2017 -0400

      Commit from branch1

  commit COMMIT_#1
  Author: Dan Hagarty <dan.hagarty.ctr@navy.mil>
  Date:   Thu Jun 1 07:09:17 2017 -0400

      first commit

git branch -d branch1
  Deleted branch branch1 (was 4906578).
git log
  commit COMMIT_#2 (HEAD -> master)
  Author: Dan Hagarty <dan.hagarty.ctr@navy.mil>
  Date:   Thu Jun 1 07:44:03 2017 -0400

      Commit from branch1

  commit COMMIT_#1
  Author: Dan Hagarty <dan.hagarty.ctr@navy.mil>
  Date:   Thu Jun 1 07:39:51 2017 -0400

    first commit
      
example create and managing branches
git init project2
Initialized empty Git repository in /home/hagartyd/repository/project2/.git/

cd project2
vim README
git add README
git commit -a -m "1st version"
[master (root-commit) adb9981] 1st version
 1 file changed, 1 insertion(+)
 create mode 100644 README

git status
On branch master
nothing to commit, working tree clean

git log
commit adb998123f0dfd6ea3b7cbb24205ba1688263fce (HEAD -> master)
Author: Dan Hagarty 
Date:   Tue May 30 14:23:50 2017 -0400

    1st version

vim README
git add README
git commit -m "2cd version"
[master 9a2c6c0] 2cd version
 1 file changed, 1 insertion(+), 1 deletion(-)

git log
commit 9a2c6c0c9c874b5c05339957e128210679ba516d (HEAD -> master)
Author: Dan Hagarty 
Date:   Tue May 30 14:28:14 2017 -0400

    2cd version

commit adb998123f0dfd6ea3b7cbb24205ba1688263fce
Author: Dan Hagarty 
Date:   Tue May 30 14:23:50 2017 -0400

    1st version

git branch branch1
git branch
  branch1
* master

git checkout branch1
Switched to branch 'branch1'

git branch
* branch1
  master
vim README
git add README
git status
On branch branch1
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   README
			
git commit -m "Added to branch1"
[branch1 40ead55] Added to branch1
 1 file changed, 1 insertion(+), 1 deletion(-)
git status
On branch branch1
nothing to commit, working tree clean

git checkout master
Switched to branch 'master'

git merge branch1
Updating 9a2c6c0..40ead55
Fast-forward
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

git status
On branch master
nothing to commit, working tree clean

git branch
branch1 
* master

git branch -d branch1
Deleted branch branch1 (was 40ead55)
 
git branch
* master

merging

Merging takes the changes from commits on another branch and puts them into the current branch. git pull uses the merge command to include changes from another repository.

example merging branches
git init project3
Initialized empty Git repository in /home/hagartyd/repository/project3/.git/

cd project3

vim myfile.txt

cat myfile.txt
This is the original myfile.txt

git add myfile.txt

git commit -a -m "First commit"
[master (root-commit) e573d9d] First commit
 1 file changed, 1 insertion(+)
 create mode 100644 myfile.txt
 
 git checkout -b branch_01
 git branch
 * branch_01
  master
  
  vim myfile.txt
  cat myfile.txt
This is the original myfile.txt
This line was added on branch_01

git add myfile.txt
git commit -m "Updated branch_01"
[branch_01 78abf62] Updated branch_01
 1 file changed, 2 insertions(+)

git branch
* branch_01
  master

git checkout master
Switched to branch 'master'

git diff branch_01
diff --git a/myfile.txt b/myfile.txt
index 2b55458..33f9d18 100644
--- a/myfile.txt
+++ b/myfile.txt
@@ -1,3 +1 @@
 This is the original myfile.txt
-This line was added on branch_01
-

git merge branch_01
Updating e573d9d..78abf62
Fast-forward
 myfile.txt | 2 ++
 1 file changed, 2 insertions(+)


The Pro Git book does a nice job explaining basic branching and merging. You can read more here.

remote branches

From the book,

Remote-tracking branches are references to the state of remote branches. They’re local references that you can’t move; they’re moved automatically for you whenever you do any network communication. Remote-tracking branches act as bookmarks to remind you where the branches in your remote repositories were the last time you connected to them.

Remote branches are displayed using the remote/branch form. Normally if you clone a remote repository, the remote name is origin. To refer to the master branch from that repository you would refer to origin master.

git fetch origin master updates references from the master branch on the remote named origin. It gets the data, but does not merge it with your local branch. You can do that manually if need be.

git push is used to push your branch up to the remote.

git pull will pull down the remote branch and merge it with your local branch. In general, it is less confusing to do a git fetch then, git merge.

where to go from here