Here we have a bunch of real-world use-case examples of git, which is #hellarad.

Git Vocabulary

Things are slightly different in git from what you may be used to. Here are a few terms we'll be throwing around and what the intended meaning is.

repo
Typically a local working directory that is a git repository as identified by the presence of a .git directory.
branch
A set of tracked changes in a repo, master is the main branch.
remote
Othet repositories that the local repo knows about, such as the project origin and perhaps an upstream
upstream
A more authoratative code base of the project, such as a central repository.

Quick Steps

Quick steps for working with an up-stream repo

git clone git://git.evergreen-ils.org/OpenSRF.git
git log --stat
git checkout -b my_work
# hack away
git commit -a
git checkout master
git merge --log --stat --no-commit my_work
git commit -a
git checkout my_work
git log --stat

Read-Only Projects

A very common use for git is to just get access to the latest code from the publisher. In this case we clone and pull, over and over. In this example we are working with OpenSRF.

. # git clone git://git.evergreen-ils.org/OpenSRF.git
. # git remote -v
. # git pull
. # git branch -a
. # git checkout remotes/origin/rel_2_1

Then I just configure, make && make install and we're ready to go.

To update this git from the origin again we simply go back to the master branch, then pull.

. # git checkout master
. # git pull

Viewing Repository Information

There is loads of git repository information stored in the ./.git directory.

. $ git status
. $ git branch -a
. $ git remote -v
. $ git log --graph --stat

Make a new Project

Making a new project is easy and git will initialise itself in the specified directory. Now git is tracking changes, to any/all files. This is useful for both code (common) and also configurations.

Track Changes in ~/coolapp
~ # mkdir coolapp
. # git init
. # git add .
. # git commit -m'initial commit'
Track Changes in /etc
~ # cd /etc
. # git init
. # git add .
. # git commit -m'initial commit'
An entire installed application, then creating a branch of this first state
~ # cd /opt/freeswitch
. # git init
. # git add .
. # git commit -m'initial commit'
. # git branch square-one

Tracking Changes

Tracking changes is done in a git branch. Create one, then checkout to make it the active branch. Then hack away, edit files, delete them, add new ones, make symlinks and all that other fun stuff. A commit will then create a snapshot of your changes.

View local, remote or all branches

. # git branch
. # git -r branch
. # git -a branch

Discarding Changes

If the files are unstaged you can simply do a checkout, or stash to save them for later. If they are staged use reset

git checkout path/to/changed/file.c

To discard all changes

git checkout -- .

Save the changes for later

git stash
git stash save --keep-index
git reset -- path/to/staged/file.c

Create Branch from head, existing branch or tag.

. # git branch new-name-here
. # git branch new-name-here copy-from-this
. # git checkout new-name-here

Create and Checkout

. # git checkout -b new-big-edit

Push Branch to Remote

git push -u origin my-branch-name
git push -u origin my-branch-name

Rename a Branch

. # git branch new-cool-name-hax0r
. # git -m new-cool-name-hax0r bug4321
. # git -M new-cool-name-hax0r existing-branch-name

Merging a Branch

Here we'll merge to master, or merge to master w/o a commit

. $ git commit
. $ git checkout master
. $ git merge bug4321
# don't commit
. $ git merge --no-commit bug4321
# bring logs, show stats
. $ git merge --no-commit --log --stat --verbose bug4321

Delete a Branch

After the branch is merged to master we can remove it, to keep things clean. If the branch has been pushed then you need to remove it from origin as well.

First example is just deleting the local branch, then force deleting - if there are untracked changes. Finaly, push the delete to the origin. Note the ':' in front of the branch name.

. # git branch -d branch_name
. # git branch -D branch_name
. # git push origin :branch_name

Amend/Edit Git Commit

This one is quite easy, if the comit was missing some changes.

git add file/you/edited.txt other/file/too.css
git commit --amend

Undo Git Commit

This first option destroys the commit as if it never happened, your edits will be lost. You can undo one or more commits this way. The first one rolls back the commit, but leaves the files as they were (staged for commit) Using --hard removes the edits you've made to the file. Each ^ is moving the state back one step.

git reset --soft 'HEAD^'
git reset --hard HEAD^
git reset --hard HEAD^^

The --soft option will undo the commit, however your edits will remain in a now uncommitted state.

git reset --soft HEAD^
git add edited/file/one.php edited/file/two.css
git commit

Revert Single Commit

Viewing Changes

Git provides the diff, log and show commands to view changes to the branches.

. # git diff HEAD^..HEAD
. # git diff HEAD^^..HEAD
. # git diff --name-only HEAD^..HEAD
. # git log
. # git log -3
. # git log HEAD^^^^^^^^..HEAD
. # git show -2
. # git show --summary

Viewing previous version (^) and previous-previous(^^) versions, file names only, negative numbers reference back from HEAD. Same style inputs for log and show commands.

Patching a git diff

You can apply the output of a git diff as a patch, just like you did back in the days before nice distributed source control.

git diff master my_branch_is_cool > diff.patch
patch -p1 < diff.patch

Upstream Remotes

Attach to Upstream Project

In this scenario we create a fork of some other project (on github) and begin working on it. Use github to create the fork, then pull this new forked-master, attach the upstream remote and begin working.

~ $ git clone git@github.com:edoceo/evergreen
~ $ cd evergreen
. $ git remote add upstream git://github.com/evergreen
. $ git pull upstream master

First the clone is taken, we change to the repo directory and add a new remote named upstream which references the original project. The fetch brings their changes in.

Staying in Sync

It's important with git, and other source control systems, to not get too far behind. However, I've found git to be much more tolerant likely due to it's branch/ref design.

SSH Key Identity Management

In many cases it's possible (probable?) that one would need to have multiple identies on some server. For example, a personal and also company account on GitHub or GitLab. These tools use ssh to push and pull from the remote. And if you have only one SSH key, there will be access control issues. This is solvable with entries in `~/.ssh/config` and then some updates to the remote url.

Host alpha.github.com
 HostName github.com
 IdentityFile ~/.ssh/id_ed25519_alpha

Host bravo.github.com
 HostName github.com
 IdentityFile ~/.ssh/id_ed25519_bravo

See the difference when accessing via ssh now

ssh -T git@gitlab.com
Welcome to GitLab, @default!
ssh -T git@alpha.gitlab.com
Welcome to GitLab, @alpha!
ssh -T git@bravo.gitlab.com
Welcome to GitLab, @bravo

Then we re-write the remote origin url using the alias defined in .ssh/config

$ git remote -v
origin	git@gitlab.com:edoceo/example.git (fetch)
origin	git@gitlab.com:edoceo/example.git (push)
$ git remote set-url origin git@alpha.gitlab.com:edoceo/example.git

See Also