Git Basics

Git Basics

Get the Repository

git clone https://github.com/rails/rails.git
cd rails

This copies the salsa repo at the given location to the salsa sub-directory.

To download updates from your original repository, and merge changes into your current branch:

git pull

To update the repo, and merge the changes yourself on your master branch

git fetch
get merge origin  # This is also called a "fast forward" merge for newer changes

To send updates to branches on the original repo:

git push

Switching Branches

What branches exist?

git branch           # Lists local branches
git branch -a        # Lists all (local + remote) branches
git branch -v        # Shows last commit message

To create the remote staging branch as your staging branch, use the checkout -b option:

git checkout -b staging origin/staging

To switch back to the master branch

git checkout master

To create an new branch, for issues, features, or experimentation:

git checkout -b 1287-purge-feature

You can do this before or after you start working, your uncommitted changed will be kept with the new branch. Your current branch is the starting point for the new branch, usually the branch in which you will merge the changes back (staging).

Sharing the Branch

If you want to send your branch up to the original repository to share it with others:

git push origin 1234-feature-branch

In order to pull changes to that branch back into your repository, you must add this to your .git/config file on the root of the repo:

[branch "1234-feature-branch"]
remote = origin
merge = refs/heads/1234-feature-branch

To remove the remote branch:

git branch -d -r origin/1234-feature-branch

Finishing the Branch

When you are done with the branch, merge it back into the original branch, and delete it

git checkout staging
git merge --no-ff 1234-feature-branch
git branch -d 1234-feature-branch

The —no-ff (no fast-forward) merge option keeps the group of commits to the source branch in a separate path, and creates a “merge” point. Fast forward merges will not show the branching history.

The -d option deletes the branch if merged. If you do not want to merge it, blow it away with the -D option

git branch -D 1234-experimental-branch

Branch Naming Conventions

Long-lived branches are common names

master: Production branch. 
staging: Beta release branch, recent features and fixes for next release

Feature and issue branches incorporate the tracker ticket number and description

ticket-issue_feature-title-of-feature-or-issue
1234-feature-title
1234-hotfix-title
1234-issue-title

Making Changes

Switch to the branch you wish to commit the change. Edit away.

What files are changed?

git status

this shows known, modified files in the first section, then (new) untracked files, and deleted files. Deleted files are removed from the repository on commit.

What are my changes I am about to commit?

git diff [--color] [--word-diff]

To restore a file to its original state, or copy from another branch:

git checkout filename        # Discard changes to it
git checkout branch filename # Cherry-pick this file from another branch/tag/commit

Rename, move and delete files:

git mv source destination  # Rename or new location
git rm files
rm files                   # git detects deleted files and will delete them too

Staging your Commit

Commits to all known files can be made with:

git commit -a
git commit -a -m'commit message'

If you want to commit only certain changed files:

git commit file file ...

If you want to also add changed files, or new files to the commit (and repository), use ‘git add’. They are then staged and committed with the next commit action.

git add file file ...
git commit

You can examine and accept/decline each chunk of change in each file. This is useful to make sure any unintended test code is not committed, and to review your work.

git commit -p

Commit Message Conventions

Refer to a tracker ticket number and type on the commit message, or start the commit message with the following action verbs: fixed, added, hotfix (I know), removed, updated, or similar.

fixes #1234 feature-name issue-description
adds #1234 feature-name description
hotfix #1234 issue description

Try to include the feature-name as the process, program or webpage name.

The commit will print out the branch name, commit hash, and commit message. Copy and paste this into the tracker ticket when resolving the issue, allowing the change to be identified and inspected later if necessary.

Workflow

Update your repository and merge changes into your current branch, switch to the starting branch (staging) and create your work branch:

git pull
git checkout staging
git checkout -b 1234-feature-name

Sometimes, you want to rebase your work on the current state of the starting branch. Rebasing removes your commits, fast-forwards the initial branch point to the current HEAD (last commit) of the starting branch. It them “replays” your commits onto the new starting point.

git pull
git rebase

After finishing your changes, test and commit, then prepare to merge back into the starting branch

git commit ...
git checkout staging
git pull                # Updates repository and fast-forwards branch
git merge --no-ff 1234-feature-name
git push                # Sends merged branch upstream
git branch -d 1234-feature-name

Interrupted Development

By keeping your work separate, you can switch back to the staging branch for a hotfix at anytime

git stash                # Stores uncommitted changes for later
git checkout staging
git pull

Make and test your changes…

git commit -a -m'hotfix #1111 ...'
git push 
git checkout 1234-feature-name
git stash apply          # Restores uncommitted changes

Large-scale Workflow

My workflow understand came from this great post

The git-flow extensions help implement and enforce this style of workflow.

Inspecting the Repository

Use the git log command to display the commit chain of a branch. On the command line it will be

git log [options] [since..until] [branch] [filenames]
git log
git log files
git log staging bl-manage
git log --pretty=oneline --abrev-commit --graph --color

You can also specify the starting and ending points to display. “since” and “until” here can be commit hashes, tags, HEAD, or not specified to indicate the beginning of time or current commit (HEAD)

since..               # From commit/tag to HEAD
since..until          # Between commits/tags
..until               # Up until the point
commithash            # This commit only

Which files changed?

Use the whatchanged command to show the changed files for the commits

git whatchanged [options] [since..until] [branch] [filenames]
git whatchanged --pretty=oneline --abbrev-commit

c260028 Fixed redirect after login (php reg globals)
:100755 100755 04816ea... 51a264a... M  www/mlm/controller/home.php
:100755 100755 0b36ac1... 0869628... M  www/mlm/main.php

Inspecting with git diff

The git diff command can show differences between two commits for all files or given files.

git diff [options] [since..until] [branch] [filenames]
git diff                    # Uncommitted changes
git diff [since..until] 
git diff --word-diff=color  # Readable diffs with red (removed) and green (added)

Inspecting a commit

The ‘git show’ command prints information from the log and diff commands together

git show [options] [since..until] [branch] [filenames]

The tig command

The tig package is a ncurses-based git browser. Very awesome.

tig
tig [options] [since..until] [branch] [filenames]

Use it to review commits, and show the revisions.

GUI Tools

Git comes with a Tcl/Tk browser:

git gui

There are several options for each platform:

  • gitweb: A web application
  • getalist: web application
  • gitorious: open-sourced web hosting platform
  • gitx: Mac OS X client

Releasing

Release are merges of changes in the staging branch into the master branch.

git checkout master
git merge --no-ff staging
git tag -a v1.2.3   # Opens commit message in editor for details
git push --tags

To update a repo, simply pull, or checkout to a tag

git fetch           # Downloads new tags, branches and commits
git pull            # Does a fetch, and merges into current branch
git checkout v1.2.3 # Sets the repo to the given tag or commit hash

Due to the distributed topology of git, once tags are pushed, they should be considered permanent.

Hotfixes

Hotfixes are added directly to the master branch, as they need to be separate from the other changed already present in the staging branch. The change should be applied to both branches, using the cherry-pick command.

git commit -a -m'hotfix #1234: can not delete records'
[staging 8cf5623] hotfix #1234: can not delete records

git pull
git checkout master
git cherry-pick 8cf5623
git push

This will copy the commit to the master branch. It will have different hash on the new branch because it is applied to a different point in the repository.

Creating a Repository

Take a project directory and make it a git repo.

cd project
git init          # Creates .git subdirectory to hold repo
vi .gitingnore    # Create file of filename patterns to ignore
  *.swp          # Like vim swap files
  *.log          # and log files
git add .         # Adds files in directory to staged commit
git commit -m'Initial commit to git' # Commit project

Now let’s share it on our network

ssh example.com
cd /path/to/git/repos/
git clone --bare originalhost:path/to/project project.git
touch project.git/git-daemon-export-ok # if using git-daemon instead of ssh
chmod -R g+w project.git  # Allow everyone to write to the repo

Point your project repo to use this new one as the origin

cd project
git config remote.origin.url ssh://example.com/path/to/project.git

Git Resources

Git command offer a —help option to show the man page

git pull --help
man git-pull

Sample ~/.gitconfig

[user]
  name = Your Name
  email = mailbox@example.com
[core]
  editor = vim
[color]
  diff = auto
  status = auto
  branch = auto
  ui = auto
  grep = auto
  ui = auto
[alias]
  co = checkout
  com = commit
  cp = cherry-pick
  c   = commit -a
  br = branch -v
  b = branch -v
  st = status
  s  = status
  d = diff --color-words
  sh = show --color-words
  l = log --pretty=oneline --abbrev-commit --graph
  ll = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
  uncommit = reset --soft HEAD^
  amend = commit --amend -C HEAD
  master = checkout master
  staging = checkout staging
  devel = checkout development
  ;send = push origin listpost-edit
[merge]
  tool = vimdiff
[rerere]
  enabled = 1