In 2012 I jumped into Git with both feet and eyes closed as the company I was working for transitioned away from CVS and Clear Case. The company was large enough to have a small team of individuals responsible for the maintenance of the repository, allowing me to be a contributor. At the time I found the concept of distributed repositories and the ability to revision all sources instead of individual files intriguing. However, as with all things, when you have the power of a star ship at your finger tips one can easily get lost in the sea of buttons, unable to remember how to disengage the locking clamps. Since that time I have been a contributor, an integration manager, and responsible for the repository with a centralized work flow. In that time, I have compiled the following notes to refer back to; these will have to suffice until I can ask Alexa “grab the changes that provide low power mode from the development branch”.

These Notes were last updated 2017-OCT-17

References

Definition of Terms

Typical Branch Naming Conventions

Master      A-----------------------E----H-------------->
             \                     /           
Development   B<--------C<--------D<-------E<----->
               \       /
Topic           F<----G

Master branch : Stable code base only bug fixes of a high severity and high priority are committed directly to the branch. Development branch may be merged in when it has become stable.

Development branch : This is the integration branch. As each of the topic branches pass a unit test which verified the functionality it gets integrated into the development branch for integration testing.

Topic/Feature Branch: Bug fixes and feature development work get their own branch. Only when the feature is complete and passes a unit test is it integrated into the development branch.

Notation

Commands When and Why to Use Them

git add

Add the files that need to be “staged” into the local repository. This not only adds new files to the repository but also must be done for files which have changed and will eventually be committed to the repository (this is called staging).

git add xtitle

Note that if one does the following

  1. git add file.txt
  2. modify file.txt
  3. git commit file.txt

ONLY THE CHANGES FROM (1) WILL BE COMMITTED IN (3). This allows one to stage changes without committing them…yet…

To unstage a file before it is committed This will remove file(s) from the staging area which were previously added but not committed. Note: The git status command supplies the correct command to execute

git reset HEAD <file>

git bisect

If one knows that some piece of functionality is broken as of a certain release and know that the functionality worked in another release then git bisect can help narrow down the commits in the release.

For this command there really isn’t a way to put it succinctly, I always reference Pro Git, Git Tools : Bisect Debugging for this one…

git blame

When you see an obvious bug and you want to tease a coworker for such an obvious mistake, but first you want to prove to yourself it was not you…

To produce an annotated file which indicates when the line was changed, why (SHA-1), and by whom:

git blame <filename>

git branch

See the list of current local branches. In the listing the branch name with the * character indicates the HEAD (i.e. the current branch checked out).

git branch

List all branches

git branch -a

Create a new branch

# At the same commit point presently on:
git branch <branchName>

# Branch from existing reference (tag or branch)
git branch <new-branch-name> <existing-ref>

Delete a branch that is no longer needed:

List which branches have been merged to a given branch

git branch -a --merged <branchName>

# This is the same thing as 
git checkout master
git branch -a --merged

Change the name of a local only branch

# While on the branch
git branch -m <newName>

# On a different branch
git branch -m <oldname> <newname>

git checkout

Switch the local repository to an existing branch. This points HEAD to another the branch associated with branchName. Any changes and commits will now be associated with the branch switched to. It also reverts the files in the working directory to the snapshot taken at branchName.

git checkout <branchName>

Revert a modified file back to what it looked like when it last committed. Danger the file is overwritten with the last version which was committed and this can not be undone.

git checkout -- <file>

Use the -b flag to create a new branch before switching to it. This is the same as using the branch option followed by another git command with the checkout option.

git checkout -b <newBranchName>

Create a tracking branch. There is a branch on the remote server which was brought down in the last fetch and one wants to work on that branch. GIT does not automatically create local editible copies of remote branches. To do this a tracking branch needs to be created then have the remote branch merged into. A tracking is local and has a direct relationship with the remote branch.

git checkout -b <localBranchName> [remoteName]/[remoteBranchName]
# A simplified version which does the same thing:
git checkout --track## remoteName]/## remoteBranchName]

Copy a file from another branch into the current branch. This command will copy fileName (must be pathed if in a subdirectory) from branchName into the current branch. If branchName does not have a tracking branch then the full branch name (e.g. origin/branchName) must be used.

git checkout branchName fileName

git cherry-pick

If you every fixed a bug on a development or feature branch and find that the fix is needed in a hot fix branch, this command is for you. Applies changes introduced in another commit into the currently checked out sources. Useful for taking a bug fix put into the trunk and back porting it into a bug fix branch.

git cherry-pick -x <commit>…

See the section Tasks below for more information

git clone

Obtain a copy of the repository to be worked on

git clone <repository> <directory>

git commit

git config

Initial user configuration

The following sets the Git individual user’s preferences and identity. The –global makes Git store this information in the user’s .gitconfig file located in their home directory. Otherwise the information would be stored on a single machine or in a single repository.

git config --global user.name "W Parker Mackenzie"
git config --global user.email "wparkermackenzie@live.com"
git config --global core.editor /usr/bin/vim
git config --global merge.tool /usr/bin/gvimdiff
git config --global diff.tool p4merge
git config --list

git diff

Viewing file changes : git diff

git fetch

Get data from a remote repository without merging that data into the local repository. :

git fetch <remote-name>

Gets all the data from the remote repository from which the local repository was initially cloned.

git fetch origin

git grep

Look for a pattern in the tracked files in the working tree

git grep <pattern>

git init

Create the initial repository

This will create what is known as a “bare repository”. This is a repository which does not have any working files or directory structure; it is just the Git data.

gitk

Favorite options:

git log

To change the log output to formats other than the default the –pretty option is used.

git merge

Merge a branch into the current branch HEAD; switch to the branch to be merged into then execute :

git merge [--no-ff|--squash] <branchName>

Incorporate changes from another repository which were obtained by a git fetch (similar to what a git pull does):

git fetch <remote>
git merge

git mv

git pull

Similar to fetch the following command will automatically fetch and then merge a remote branch into the current branch:

git pull

git push

Push one’s changes to the remote repository

Tags are not automatically pushed to remotes via git push. This must be done explicitly:

git push origin [tagName]

Push a branch up to a remote

git push origin [branchName]

# Use this if the local branch name is not what is to be used
# on the public repository
git push origin [localBranchName]:[remoteBranchName]

Delete a remote branch use the following obtuse syntax:

# Original obtuse syntax
git push [remoteName] :[remoteBranchName]

# Cleaner syntax introduced in v1.7.0
git push origin --delete <branchName>

Use the -f force flag to override the repository’s behavior of requiring one to be up to date with the remote before the push. The flag will cause commits to be lost. This is useful when one mistakenly pushes a set of commits to a branch and then needs to reset the branch to a previous state then push the reset branch to the server.

git rebase

Similar in merge in that it takes changes from one branch and puts them into another; this is done by replaying a series of commits. Extremely useful when on a long lived feature branch and one needs to pick up changes from the sources it was branched from. A swiss army knife for more powerful merging, as with all knives it is sharp…

GENERAL RULE OF THUMB… DO NOT REBASE COMMITS THAT HAVE ALREADY BEEN PUSHED TO A SHARED REPOSITORY

Take changes from a main line and integrate them into a branch. This makes the history cleaner when the branch is merged back onto the mainline (e.g. master).

git checkout <branchName>
git rebase master

# Or all on one line
git rebase master <branchName>

Take the changes associated with branch2 which is based on branch1 and integrate them into the main line (e.g. master) use the onto flag from within branch2:

git checkout <branchName2>
git rebase --onto master <branchName1> <branchName2>
git checkout master
git merge <branchName2>

Squash all commits on the same branch into a single commit.

git rebase -I HEAD~n

git reset

Reset the current HEAD to to a specified state

To reset a branch to exactly match a remote branch. The following works well if one forgot to work off of a feature branch and applied changes to a remote branch by accident (forcing a pull which will cause a merge).

git checkout myBranch
# To save the changes to another branch just in case one wants them
git commit -a
git branch myBranch_saved

# Reset the branch back to the origin
git reset --hard origin/myBranch

If the changes were mistakenly pushed to the remote repository, after the reset, use the –force flag at the end of the line to push the changes. e.g. git push origin myBranch –force

git revert

Undoes a single commit. Instead of removing the commit the commit is undone and appends a new commit with the results.

git revert <hash/tag>

This is no panacea, if there were other changes to the files which are affected by the revert then there will be conflicts which will need to be resolved…

Revert for single commits is simple and can be thought of an undo button; however for merges it is a totally different story. Reverting a merge can be done but is not straightforward… Merge wisely or the consequences will be an hour of ones life gone to figuring this out and the uneasyness of not knowing how things are going to turn out when the merge needs to happen at a later time… To re-merge one needs to revert the revert… argh More info here

git rev-parse

Used to obtain the SHA1 of a given local tag or branch.

git rev-parse HEAD

# Or specify another branch
git rev-parse master

To obtain the SHA1 tag of a remote repository use ls-remote

git ls-remote <URL>
git ls-remote

git remote

To determine the remote repository associated with the local repository

git remote -v

Add a new remote repository

git remote add <remoteShortName> <url>

To remove a remote repository

git remote rm <remoteShortName>

git rm

git show

Show information about a git object; including the name, contact information, and tagging message. An object can be a blob, tree, tag, or commit:

git show <object>

# Show a file from another branch:
git show [branch]:[file]

git stash

To switch branches without committing work the following command takes the modified tracked files and saves them on a stack of unfinished changes that can be reapplied later:

git stash

To see what has been stashed:

 git stash list

To reapply the stashed changes :

git stash apply

It is also possible to do all sort of funky things like apply stashed changes to another branch and stash multiple changes and apply them out of order. See Pro Git, Git Tools : Stashing for more information

I have come to prefer an alternate method when I have to move from one branch to another in the middle of doing work. If I am not ready to commit my changes then I simply create a branch where I am and then merge it back in later (git checkout -b branchName )

git status

Check on the status of the files

To simply determine which files are in which state

git status

git tag

List all of the available tags.

# Lists all tags in alphabetical order
git tag

# List tags for a particular pattern, supply the list pattern flag
git tag -l "ver1.2.*"

Create a tag

# Create a tag at the head of the local repository
#Using tags in this way stores the tagger name, contact information, and the tagging message. 
git tag -a <tagName> -m "<taggingMessage>"

# Create a tag given a previous commit:
git tag -a <tagName> -m "<taggingMessage>" <commitChecksum>

Tags are not automatically pushed to remotes via git push. This must be done explicitly:

git push origin [tagName]

Tasks

Import Existing Sources Into a New Repository

  1. Create the repository in one’s favorite cloud repo (git-hub, bit-bucket, kiln, etc…), obtain the URL of the created repository (e.g. ssh://wpmackenzie@bitbucket.com/newrepo)
  2. cd newrepo where newrepo contains the sources to be imported
  3. Execute teh following git commands
     git init
     git add .
     git commit -a
     git remote add origin ssh://wparkermackenzie@bitbucket.com/newrepo
     git pull origin master
     git push origin master
    

Create Branch from Tag

# Find the tag to create the branch from
git tag|sort

# Move gits focus onto the sources associated with the tag. 
git checkout <tagname>

# Create a new branch from the sources associated with the tag and move 
# the focus of git to this new branch.
git checkout -b <branchName>

# ...Make the changes...

# Commit the changes
git commit -a

git push origin <branchName>
git tag -a <newTagName>
git push origin <newTagName>

Rename a tag

	git tag <newname> <oldname>
	git tag -d <oldname>
	git push origin --delete <oldname>
	git push origin <newname>

Rename a branch

Can’t really be done remotely. Best that can be done is to rename it locally, remove the old branch remotely, then push the new branch.

git checkout <oldname>
git branch -m <oldname> <newname>
git push origin --delete <oldname>
git push origin <newname>

Argh… notice that renaming a branch has the oldname newname swapped from the process of renaming a tag…

Create a temporary change/feature branch

In the world of GIT almost every change is a branch which makes most branches temporary. In this case a change is made on its own branch, unit tested, then merged back into one or more release branches. In this case the branch used to unit test the change can be removed once the change has been merged onto one or more of the release branches.

# Move git's focus to the sources associated where the unit 
# change is to be made.
git checkout <tagName>

# Create a new branch from the sources associated with tagName 
# and move the focus of git to this new branch.
git checkout -b <unit-branchname>

# ...Make the changes...

# Commit the changes
git commit -a

# Test the changes…iterate through Make the changes until happy ...

# Checkout the tag name associated with the release branch 
# to place the change, or put it onto the master branch.
git checkout <releaseTagName>

#  Merge in the changes from the branch
git merge <unit-branchname>

# Check and test the merge...

# No longer need the temporary branch where the original changes were made
git branch -d <unit-branchname> 

# Push the changes to the origin "pristine" repository
git push origin 

Merge individual changes into a previous branch

Here changes were made to newer version of the repository, those changes need to be back ported to an older branch. The merge and rebase commands do not work as they try to merge too much . For example :

                           origin/master
                                ↓
	(C0)<-(C1)<-(C2)←(C3)←(C4)
	       ↑                ↑
	      (C1')            (C5)
	       ↑                ↑
   origin/bugfix_branch  remote/master

In this case someone made a change (C5) on the master branch. However, after making the change it was concluded that the change also needed to get back ported to the bugfix_branch. In this case the following commands take/cherry-pick the changes from (C5) and bring them onto the bugfix_branch:

git fetch remote/master

# Create a tracking branch
git checkout -b bugfix_branch origin/bugfix_branch

git cherry-pick -x remote/master

# Follow the directions; if there are conflicts, fix the conflicts then add them.

Look at the differences between 2 branches

# This will show a textual diff of the 2 branches
git diff branch1..branch2

Or for a graphical representation (meld is my favorite…):

# This will use the diff tool configured for the user (git config --global diff.tool)
git difftool branch1..branch2

What changes do I have which have not been pushed to the origin

git diff origin/master..HEAD

Debugging Access to a Repository

Working with bit bucket, git hub, and fogbugz; from time to time access to the remote repository will be less than stellar. When logging a support ticket the following command can be helpful

date; GIT_TRACE=2 GIT_CURL_VERBOSE=2 GIT_TRACE_PERFORMANCE=2 GIT_TRACE_PACK_ACCESS=2 GIT_TRACE_PACKET=2 GIT_TRACE_PACKFILE=2 GIT_TRACE_SETUP=2 GIT_TRACE_SHALLOW=2 git clone <REPOSITORY>;date

# Where <repository> is the repository to be cloned. 

Work Flows

Integration-Manager Work Flow : As a manager

Integration-Manager Work Flow : As a contributor

Centralized Work Flow

Everyone has a clone of the blessed repository which stores the project and everyone may push to it.

This is the best way of working fast in small teams where trust is had amongst team mates.

Processes :

Git Flow

Typically a centralized repository with very specific branch naming conventions with a well defined process. More notes later on this great way to take source control out of the wild west by adding a touch of process.