Git

From Attie's Wiki
Revision as of 14:55, 4 January 2017 by Attie (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

My git cheat sheet! See also: svn and hg

This might also be useful: http://git.or.cz/course/svn.html#branch

git-stitch-repo

git-daemon

Note: By the way... there is a system-wide config file, here: /etc/gitconfig

Contents

Commands

command description
git clone ${path} retrieves the entire git repository to your local disk
git clone --mirror --bare ${path} clones the repository, use git fetch --all later to update it
git pull pulls any new revisions from the original path
git push pushes local revisions to the original path
git commit commits to the LOCAL repository
git status status since last commit
git tag lists the avaliable tags
git show ${branch/commit/tag} show details of the commit or tag
git checkout ${branch/commit/tag} changes the working copy to the tag specified
git reset --hard reverts all changes, to the currently checked out tag
git reset --soft HEAD^ reverts the HEAD pointer to the previous, but KEEPS your changes and index
git reflog shows a simple log with 7 characters of the has, refspec and commit message
git fsck shows information about dangling blobs/commits etc...
git fetch ${remote-repo} ${remote-branch}:${local-branch} fetches the remote branch
git push origin master:master first-time push
git push ${remote-repo} ${remote-branch}:${local-branch} push the branch
git remote add ${local-identifier} ${remote-address} add a remote server that you are able to push to
git branch -a list all branches remote and local
git branch --set-upstream ${branch} ${remote/branch} setup the existing branch to track remote/branch
git branch ${branch} -u ${remote/branch} setup the existing branch to track remote/branch
git apply ${patch-file} apply a patch
git archive ${branch/commit/tag} output a tarball of the given tag to stdout

~/.gitconfig

[user]
  name = "Attie Grande"
  email = "attie@attie.co.uk"
  signingkey = 0x........
 
[alias]
  st = status
  ci = commit -v
  co = checkout
  re = remote -v
  br = branch -va
  fe = fetch -p
  dc = diff --cached
  p5 = push origin master~5:master
  tg = tag -s
  lg = log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --date-order
  lg2 = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --date-order
 
[color]
  ui = true
 
[push]
  default = simple
 
[credential]
  helper = store

First push into a fresh repository

git add x y z
git ci -m "first"
git push origin master

Test for a repository

REPO=$(GIT_DIR=${TEST_DIR} git rev-parse --git-dir 2>/dev/null)

Delete all untracked files

BE CAREFUL WITH THIS

rm -rf $(git st | awk 'BEGIN{ keep=0 }{if ($0 == "# Untracked files:") { keep = 1 } else if (keep == 1 && NF == 2) { print $2 } }')

Redo last commit

git commit ...
git reset --soft HEAD^      # 1
# edit files                # 2
git add ....                # 3
git commit -c ORIG_HEAD     # 4
  1. This is most often done when you remembered what you just committed is incomplete, or you misspelled your commit message, or both. Leaves working tree as it was before "reset".
  2. Make corrections to working tree files.
  3. Stage changes for commit.
  4. "reset" copies the old head to .git/ORIG_HEAD; redo the commit by starting with its log message. If you do not need to edit the message further, you can give -C option instead.

Merging

There are a few ways to merge. These are the useful arguments

--ff-only This is useful when you are trying to merge a change from another branch, and this branch hasn't changed in the meantime
--no-ff generate a merge commit even if it could have been fast forwarded
--log add the one-line messages from commits merged
--stat show stats after the merge

Rename a remote (and local) branch

git branch -m master master-old
git push remote :master          # delete master
git push remote master-old       # create master-old on remote
git checkout -b master some-ref  # create a new local master
git push remote master           # create master on remote

You may need to change your .git/config file to update the remote branch tracking

This can also create issues for people who have the re-named branch checked out...

Modify committer's name/email

git filter-branch --commit-filter '
        if [ "${GIT_COMMITTER_NAME}" = "${OLD_NAME}" ];
        then
                GIT_COMMITTER_NAME="${NEW_NAME}";
                GIT_AUTHOR_NAME="${NEW_NAME}";
                GIT_COMMITTER_EMAIL="${NEW_EMAIL}";
                GIT_AUTHOR_EMAIL="${NEW_EMAIL}";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD

Import SVN history into a new GIT repoistory

Extract an SVN subtree - Import into Git
Simples! The 'users.txt' file looks like this:

attie = Attie Grande <attie@attie.co.uk>
git svn init http://subversion/repo --no-metadata ./repo
cd repo
git config svn.authorsfile ../users.txt
git svn fetch
 
git remote add origin /path/to/new/git/repo
git push origin master:master

Delete a tag from the remote repository

git tag -d 12345
git push origin :refs/tags/12345

Bisect

git co -b bug_hunting   # first create a branch from where you are
 
git bisect start
git bisect bad HEAD     # you are probably at a bad commit already...
 
git co ${TAG_OR_COMMIT} # locate a good commit, jumping back large chunks at a time, e.g: release tags
 
git bisect good HEAD    # once you have a good commit

Git will now checkout a commit between the commits you marked as 'good' and 'bad', you should now re-build the system or test it to determine if this commit is good or bad.
Once you have determined the quality of this commit, run git bisect good HEAD or git bisect bad HEAD and you will be presented with another commit to try.

When git has done everything it can, you will be presented with something like this:

e5c4076f317a050db38cd4cc7fc8f6c95f4d79e8 is the first bad commit
commit e5c4076f317a050db38cd4cc7fc8f6c95f4d79e8
Author: Attie Grande <attie@attie.co.uk>
Date:   Mon Feb 27 20:18:05 2012 +0000
 
    tidied up as much as possible when client disconnects
 
:100644 100644 fecca9786415c209e2d62998e39c07a7134c873b 2678b82757ffa7d0c76983af652652368c5f1067 M      TODO
:100644 100644 fa88798b08649a176f5f9e00d4fb959841b8c07c 0d28402348ece19788b6c6818148723022d959d2 M      net.c
:100644 100644 23f3c4cd8f12fab264e4d007474d53df3bb5f3b5 e0ab1dfde0c5ed3dd28e0b12d5d2d1a0d47fe482 M      net_io.c

Git is now showing you the first bad commit (e5c4076f317a050db38cd4cc7fc8f6c95f4d79e8).
The files mentioned are those that were modified in this commit.
Doing a command like git diff 23f3c4cd8f12fab264e4d007474d53df3bb5f3b5 e0ab1dfde0c5ed3dd28e0b12d5d2d1a0d47fe482 will show you the changes in the relevant file (net_io.c - the problem file!).

The bisect tool is just another argument for many small commits - the will be a smaller diff to wade through!

Authentication (HTTP)

WARNING: You didn't hear this from me... You should never use it (think SSH with keys)

If you're using HTTP to access a repository, you can add the following lines to your configuration files:

~/.gitconfig

[credential]
  helper = store

~/.git-credentials

http://username:password@server/

Committing with a specified timestamp

Use the GIT_AUTHOR_DATE and/or GIT_COMMITTER_DATE environment variable.
For example, +/- xhrs:

#!/bin/bash -ue
 
if [ $# -lt 2 ] || [ "$1" == "" ]; then
  echo "$0 [+|-]<hrs> command ..."
  exit 1
fi
 
HRS=$1
shift
 
if [ "`echo ${HRS} | cut -b1`" != "+" ] && [ "`echo ${HRS} | cut -b1`" != "-" ]; then
  HRS=+${HRS}
fi
 
DATE=$(date -d @$(echo $(date +%s)${HRS}*60*60 | bc))
 
export GIT_AUTHOR_DATE=${DATE}
export GIT_COMMITTER_DATE=${DATE}
 
git "$@"
 
unset GIT_AUTHOR_DATE
unset GIT_COMMITTER_DATE

Getting the first tag that contains a file

Tig?

#!/usr/local/bin/bash
if [ "$1" == "" ]; then
        echo "usage: $0 <filename>"
        exit 1
fi
 
if [ ! -e $1 ]; then
        echo "$0: File does not exist ($1)"
        exit 1
fi
 
echo -en "Finding first commit..."
COMMIT=`git log --pretty=oneline "$1" | tail -n 1 | cut -d " " -f 1`
if [ "$COMMIT" == "" ]; then
        echo "$0: Error while retrieving commits for file \"$1\""
        exit 1
fi
 
echo -en "\rFinding tags containing commit $COMMIT..."
git tag -l --contains "$COMMIT" > /tmp/tag_contains
if [ "$?" != "0" ]; then
        echo "$0: Error while retrieving tags containing commit \"$COMMIT\""
        exit 1
fi
 
echo -en "\rFinding first tag that contains $COMMIT..."
git for-each-ref --sort='-*authordate' --format='%(tag)' refs/tags/ |
while read a; do
        if [ "$a" == "" ]; then
                continue
        fi
        grep "$a" /tmp/tag_contains > /dev/null
        if [ "$?" == "0" ]; then
                LAST=$a
        else
                echo "$LAST" > /tmp/tag_first
                break
        fi
done
TAG=`cat /tmp/tag_first`
rm /tmp/tag_contains /tmp/tag_first
 
echo -en "\rFinding tag information..."
INFO=`git show "$TAG" | head -n 3 | tail -n 2`
if [ "$INFO" == "" ]; then
        echo "$0: Error retrieving info for tag \"TAG\" (maybe it isn't annotated?)"
        exit 1
fi
 
echo -en "\r\0033[K"
echo -e "File:\t\t$1"
echo -e "First tag:\t$TAG"
echo "$INFO" | sed -re 's/^(.+):[ ]+(.+)$/\1:\t\t\2/'
Personal tools
Namespaces

Variants
Actions
Navigation
Toolbox