Git: Distributed Version Control System

Git is used more and more popular in projects. It becomes more important in software developer’s life. In this article, I’ll give a short description of installing latest version of Git, and then configure Git to improve work efficiency.

Git Theory

The following figure shows the important concepts of Git:

Git_Note

Git Cheat Sheet from git-scm.com:

Git Cheat Sheet

Git Cheat Sheet from zeroturnaround.com

Git Hooks

Git hooks are programs you can place in a hooks directory to trigger actions at certain points in git’s execution. By default the hooks directory is $GIT_DIR/hooks, but that can be changed via the core.hooksPath configuration variable:

chenwx@chenwx ~/linux $ ll .git/hooks/
-rwxrwxrwx 1 chenwx chenwx  478 Jul 22  2016 applypatch-msg.sample
-rwxrwxrwx 1 chenwx chenwx  896 Jul 22  2016 commit-msg.sample
-rwxrwxrwx 1 chenwx chenwx  189 Jul 22  2016 post-update.sample
-rwxrwxrwx 1 chenwx chenwx  424 Jul 22  2016 pre-applypatch.sample
-rwxrwxrwx 1 chenwx chenwx 1.7K Jul 22  2016 pre-commit.sample
-rwxrwxrwx 1 chenwx chenwx 1.4K Jul 22  2016 pre-push.sample
-rwxrwxrwx 1 chenwx chenwx 4.9K Jul 22  2016 pre-rebase.sample
-rwxrwxrwx 1 chenwx chenwx 1.3K Jul 22  2016 prepare-commit-msg.sample
-rwxrwxrwx 1 chenwx chenwx 3.6K Jul 22  2016 update.sample

Git hooks that don’t have the executable bit set are ignored, so you may need to change the file permissions of the script if you’re creating it from scratch:

chenwx@chenwx ~/linux $ touch pre-commit
chenwx@chenwx ~/linux $ chmod +x pre-commit

Before Git invokes a hook, it changes its working directory to either $GIT_DIR in a bare repository or the root of the working tree in a non-bare repository. An exception are hooks triggered during a push (pre-receive, update, post-receive, post-update, push-to-checkout) which are always executed in $GIT_DIR.

Hooks can get their arguments via the environment, command-line arguments, and stdin.

Git hooks are scripts that run automatically every time a particular event occurs in a Git repository. They let you customize Git’s internal behavior and trigger customizable actions at key points in the development life cycle. Common use cases for Git hooks include encouraging a commit policy, altering the project environment depending on the state of the repository, and implementing continuous integration workflows. But, since scripts are infinitely customizable, you can use Git hooks to automate or optimize virtually any aspect of your development workflow.

The built-in scripts of Git hooks are mostly shell and PERL scripts, but you can use any scripting language you like as long as it can be run as an executable. The shebang line (#!/bin/sh) in each script defines how your file should be interpreted. So, to use a different language, all you have to do is change it to the path of your interpreter. For instance, you can write an executable Python script in the prepare-commit-msg file instead of using shell commands:

#!/usr/bin/env python
import sys, os
commit_msg_filepath = sys.argv[1]
with open(commit_msg_filepath, 'w') as f:
f.write("# Please include a useful commit message!")

Hooks are local to any given Git repository, and they are not copied over to the new repository when you run git clone. And, since hooks are local, they can be altered by anybody with access to the repository. This has an important impact when configuring hooks for a team of developers. First, you need to find a way to make sure hooks stay up-to-date amongst your team members. Second, you can’t force developers to create commits that look a certain way—you can only encourage them to do so.

Maintaining hooks for a team of developers can be a little tricky because the .git/hooks directory isn’t cloned with the rest of your project, nor is it under version control. A simple solution to both of these problems is to store your hooks in the actual project directory (above the .git directory). This lets you edit them like any other version-controlled file. To install the hook, you can either create a symlink to it in .git/hooks, or you can simply copy and paste it into the .git/hooks directory whenever the hook is updated.

As an alternative, Git also provides a Template Directory mechanism that makes it easier to install hooks automatically. All of the files and directories contained in this template directory are copied into the .git directory every time you use git init or git clone.

Also refer to:

Git Protocol Version 2

The main improvements of Git protocol version 2 specification are:

  • Server-side filtering of references
  • Easy extensibility for new features like ref-in-want and fetching and pushing symrefs
  • Simplified client handling of the http transport

The Git protocol version 2 is already merged to Git 2.18, refer to release notes.

Refer to Introducing Git protocol version 2.

Install Git by Compiling

If you have Git installed in system but not the latest version, you properly want to install latest version of Git to experience the new features of it.

Install needed packages

$ sudo apt-get update
$ sudo apt-get install libcurl4-openssl-dev libexpat1-dev asciidoc xsltproc xmlto docbook2x

Clone Git Repo

By following command, you can download Git source code to directory ~/git from its official website:

~ $ git clone git://git.kernel.org/pub/scm/git/git.git

or, from github repository:

~ $ git clone https://github.com/git/git.git

Build and Install Git

First, check version of installed Git by command:

~/git $ git --version

Then, check out specific tag of Git source code:

~/git $ git checkout master
~/git $ git pull
~/git $ git tag -l | tail
  v2.3.3
  v2.3.4
  v2.3.5
  v2.4.0-rc0
~/git $ git checkout v2.3.5

Now, it’s time to build and install Git (including doc, html and info):

~/git $ make prefix=/usr all doc info
~/git $ sudo make prefix=/usr install install-doc install-html install-info

The latest version of Git is installed:

~/git $ git --version

Remember to clean-up the Git source directory:

~/git $ make distclean
~/git $ git checkout master

Git Configure

The Git configuration git-config.conf used in my work and personal projects improves work efficiency, which can be included in .bashrc.

The following command shows the Git configuration:

# Show the configuration applied to all users in the system
$ git config --system -l

# Show the configuration applied to all repositories of an user
$ git config --global -l

# Show the configuration applied to the current repository
$ git config --local -l

# Show the alias of configurations
$ git config -l | grep alias.
alias.br=branch
alias.co=checkout
alias.ci=commit
alias.st=status
alias.dt=difftool
alias.mt=mergetool
alias.desc=describe
...

Useful Commands

List All Files with Absolute Path in a Commit

If you want to print the absolute path of a commit, you could execute the script git-ls.sh to print the files changed by a commit with absolute path:

chenwx@chenwx ~/linux/arch/x86/kernel $ . ~/git-ls.sh 90a2282e23f0
/home/chenwx/linux/arch/x86/include/asm/irq.h /home/chenwx/linux/arch/x86/kernel/apic/vector.c /home/chenwx/linux/arch/x86/kernel/irq.c

chenwx@chenwx ~/linux/arch/x86/kernel $ git lc 90a2282e23f
commit 90a2282e23f0522e4b3f797ad447c5e91bf7fe32
Author:     Thomas Gleixner <tglx@linutronix.de>
AuthorDate: Thu Dec 31 16:30:53 2015 +0000
Commit:     Thomas Gleixner <tglx@linutronix.de>
CommitDate: Fri Jan 15 13:44:01 2016 +0100

    x86/irq: Call irq_force_move_complete with irq descriptor

    First of all there is no point in looking up the irq descriptor again, but we
    also need the descriptor for the final cleanup race fix in the next
    patch. Make that change seperate. No functional difference.

    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Tested-by: Borislav Petkov <bp@alien8.de>
    Tested-by: Joe Lawrence <joe.lawrence@stratus.com>
    Cc: Jiang Liu <jiang.liu@linux.intel.com>
    Cc: Jeremiah Mahler <jmmahler@gmail.com>
    Cc: andy.shevchenko@gmail.com
    Cc: Guenter Roeck <linux@roeck-us.net>
    Cc: stable@vger.kernel.org #4.3+
    Link: http://lkml.kernel.org/r/20151231160107.125211743@linutronix.de
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

 arch/x86/include/asm/irq.h    |  5 +++--
 arch/x86/kernel/apic/vector.c | 11 +++++++----
 arch/x86/kernel/irq.c         |  2 +-
 3 files changed, 11 insertions(+), 7 deletions(-)

Show Root Directory of Git Repository

Run the following commands to show the local git repository (.git):

chenwx@chenwx ~/xx-net/code/default/x_tunnel/local $ pwd
/home/chenwx/xx-net/code/default/x_tunnel/local

# Show the location of .git/ directory of currenty local repository
chenwx@chenwx ~/xx-net/code/default/x_tunnel/local $ git rev-parse --git-dir
/home/chenwx/xx-net/.git

# Show the working area of current local repository (absolute path)
chenwx@chenwx ~/xx-net/code/default/x_tunnel/local $ git rev-parse --show-toplevel
/home/chenwx/xx-net

# Show the working area of current local repository (relative path)
chenwx@chenwx ~/xx-net/code/default/x_tunnel/local $ git rev-parse --show-prefix  
code/default/x_tunnel/local/

# The deepth from current directory to the root directory of working area
chenwx@chenwx ~/xx-net/code/default/x_tunnel/local $ git rev-parse --show-cdup  
../../../../

Show Remotes

The following command shows the remotes:

$ git remote -v

Then, use the following command to show detail information of specific remote:

$ git remote show <remote>

Show Summarize of Commits

The following command shows summarize of git log output:

$ git shortlog

Archive Specified Commit

Archive the latest version of repository:

chenwx@chenwx /media/chenwx/Work/blog $ git rev-parse --short HEAD
94f0da70a606

chenwx@chenwx /media/chenwx/Work/blog $ git archive -o commit-`git rev-parse --short HEAD`.zip HEAD

chenwx@chenwx /media/chenwx/Work/blog $ ll commit-94f0da70a606.zip
-rwxrwxrwx 1 chenwx chenwx 18M Jul 21 19:13 commit-94f0da70a606.zip

or, use the script git-archive.sh to archive the specified commit.

List Tags with Sorting

Use the following command to list tags with sorting:

chenwx@chenwx ~/linux $ git tag -l v[0-9]* --sort=v:refname
v2.6.11
v2.6.11-tree
v2.6.12
v2.6.12-rc2
v2.6.12-rc3
v2.6.12-rc4
v2.6.12-rc5
v2.6.12-rc6
v2.6.12.1
v2.6.12.2
v2.6.12.3
...

Update Author and Commiter’s Name and Email

Use the following command to reset author’s / commiter’s name and email for commit and commits after it:

git rebase -i <commit> --exec 'git commit --amend --reset-author --no-edit'

Clean All Untracked Files

First, use the following command to show what would be removed without actually remove anything:

git clean -nfxd

Then, use the following command to remove untracked files:

git clean -fxd

Git Clients

References