Git
m |
m (→~/.gitconfig) |
||
(58 intermediate revisions by one user not shown) | |||
Line 1: | Line 1: | ||
− | My git cheat sheet! See | + | My git cheat sheet! See also: [[svn]] and [[hg]] |
This might also be useful: http://git.or.cz/course/svn.html#branch | This might also be useful: http://git.or.cz/course/svn.html#branch | ||
− | {| | + | [https://metacpan.org/module/git-stitch-repo git-stitch-repo] |
+ | |||
+ | [[git-daemon]] | ||
+ | |||
+ | {{note|By the way... there is a system-wide config file, here: <code>/etc/gitconfig</code>}} | ||
+ | |||
+ | ==Commands== | ||
+ | {|class="wikitable" | ||
|- | |- | ||
! command !! description | ! command !! description | ||
|- | |- | ||
− | | git clone '' | + | | git clone ''${path}'' || retrieves the entire git repository to your local disk |
+ | |- | ||
+ | | git clone --mirror --bare ''${path}'' || ''clones'' the repository, use <code>git fetch --all</code> later to update it | ||
|- | |- | ||
| git pull || pulls any new revisions from the original path | | git pull || pulls any new revisions from the original path | ||
Line 19: | Line 28: | ||
| git tag || lists the avaliable tags | | git tag || lists the avaliable tags | ||
|- | |- | ||
− | | git checkout '' | + | | 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 --hard || reverts all changes, to the currently checked out tag | ||
|- | |- | ||
− | | git fetch '' | + | | 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 origin master:master || first-time push | ||
|- | |- | ||
− | | git 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 | ||
+ | |- | ||
+ | | <s>git branch --set-upstream ''${branch}'' ''${remote/branch}''</s> || <s>setup the existing ''branch'' to track ''remote/branch''</s> | ||
+ | |- | ||
+ | | git branch ''${branch}'' -u ''${remote/branch}'' || setup the existing ''branch'' to track ''remote/branch'' | ||
+ | |- | ||
+ | | git apply ''${patch-file}'' || apply a patch | ||
|- | |- | ||
− | | git | + | | git archive ''${branch/commit/tag}'' || output a tarball of the given tag to stdout |
|} | |} | ||
− | ==.gitconfig== | + | ==~/.gitconfig== |
<source lang="ini"> | <source lang="ini"> | ||
[user] | [user] | ||
− | name = "Attie Grande" | + | name = "Attie Grande" |
− | email = "attie@attie.co.uk" | + | email = "attie@attie.co.uk" |
+ | signingkey = 0x........ | ||
[alias] | [alias] | ||
− | st = status | + | st = status |
− | ci = commit -v | + | 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 | ||
</source> | </source> | ||
Line 50: | Line 96: | ||
</source> | </source> | ||
− | == | + | ==Test for a repository== |
+ | <source lang="bash"> | ||
+ | REPO=$(GIT_DIR=${TEST_DIR} git rev-parse --git-dir 2>/dev/null) | ||
+ | </source> | ||
+ | |||
+ | ==Delete all untracked files== | ||
+ | '''BE CAREFUL WITH THIS''' | ||
+ | <source lang="bash"> | ||
+ | rm -rf $(git st | awk 'BEGIN{ keep=0 }{if ($0 == "# Untracked files:") { keep = 1 } else if (keep == 1 && NF == 2) { print $2 } }') | ||
+ | </source> | ||
+ | |||
+ | ==Redo last commit== | ||
<source lang="bash"> | <source lang="bash"> | ||
git commit ... | git commit ... | ||
Line 62: | Line 119: | ||
# Stage changes for commit. | # Stage changes for commit. | ||
# "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. | # "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== | ||
+ | <source lang="bash"> | ||
+ | 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 | ||
+ | </source> | ||
+ | You may need to change your <code>.git/config</code> 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== | ||
+ | <source lang="bash"> | ||
+ | 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 | ||
+ | </source> | ||
+ | |||
+ | ==Import SVN history into a new GIT repoistory== | ||
+ | [[Extract an SVN subtree - Import into Git]]<br> | ||
+ | Simples! The 'users.txt' file looks like this: | ||
+ | <source lang="text"> | ||
+ | attie = Attie Grande <attie@attie.co.uk> | ||
+ | </source> | ||
+ | <source lang="bash"> | ||
+ | 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 | ||
+ | </source> | ||
+ | |||
+ | ==Delete a tag from the remote repository== | ||
+ | <source lang="bash"> | ||
+ | git tag -d 12345 | ||
+ | git push origin :refs/tags/12345 | ||
+ | </source> | ||
+ | |||
+ | ==Bisect== | ||
+ | <source lang="bash"> | ||
+ | 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 | ||
+ | </source> | ||
+ | |||
+ | 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.<br> | ||
+ | Once you have determined the quality of this commit, run <code>git bisect good HEAD</code> or <code>git bisect bad HEAD</code> 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: | ||
+ | <source lang="text"> | ||
+ | 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 | ||
+ | </source> | ||
+ | |||
+ | Git is now showing you the first bad commit (<code>e5c4076f317a050db38cd4cc7fc8f6c95f4d79e8</code>).<br> | ||
+ | The files mentioned are those that were modified in this commit.<br> | ||
+ | Doing a command like <code>git diff 23f3c4cd8f12fab264e4d007474d53df3bb5f3b5 e0ab1dfde0c5ed3dd28e0b12d5d2d1a0d47fe482</code> will show you the changes in the relevant file (<code>net_io.c</code> - 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==== | ||
+ | <source lang="ini"> | ||
+ | [credential] | ||
+ | helper = store | ||
+ | </source> | ||
+ | |||
+ | ====~/.git-credentials==== | ||
+ | <source lang="ini"> | ||
+ | http://username:password@server/ | ||
+ | </source> | ||
+ | |||
+ | ==Committing with a specified timestamp== | ||
+ | Use the <code>GIT_AUTHOR_DATE</code> and/or <code>GIT_COMMITTER_DATE</code> environment variable.<br> | ||
+ | For example, +/- ''x''hrs: | ||
+ | <source lang="bash"> | ||
+ | #!/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 | ||
+ | </source> | ||
==Getting the first tag that contains a file== | ==Getting the first tag that contains a file== |
Latest revision as of 15:55, 4 January 2017
My git cheat sheet! See also: svn and hg
This might also be useful: http://git.or.cz/course/svn.html#branch
/etc/gitconfig
[edit] 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 ${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 |
[edit] ~/.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
[edit] First push into a fresh repository
git add x y z git ci -m "first" git push origin master
[edit] Test for a repository
REPO=$(GIT_DIR=${TEST_DIR} git rev-parse --git-dir 2>/dev/null)
[edit] 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 } }')
[edit] Redo last commit
git commit ... git reset --soft HEAD^ # 1 # edit files # 2 git add .... # 3 git commit -c ORIG_HEAD # 4
- 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".
- Make corrections to working tree files.
- Stage changes for commit.
- "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.
[edit] 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 |
[edit] 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...
[edit] 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
[edit] 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
[edit] Delete a tag from the remote repository
git tag -d 12345 git push origin :refs/tags/12345
[edit] 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!
[edit] Authentication (HTTP)
If you're using HTTP to access a repository, you can add the following lines to your configuration files:
[edit] ~/.gitconfig
[credential] helper = store
[edit] ~/.git-credentials
http://username:password@server/
[edit] 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
[edit] 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/'