# Git notes Here are some notes I find handy for using git. * Looking at stuff * __ o See a log of commits. => git log --graph --decorate --stat # Good compromise git log --graph --decorate --stat -p # To see detailed diffs git log --graph --decorate --oneline # For longer histories <= o See the origin and branches of a working copy: => git config --get remote.origin.url git remote show origin git config -l git branch -a -v <= o See the unique hash for any file: => git hash-object --no-filters filename <= o See if a file ``Foo.java'' is being tracked, maybe just staged for a commit => git ls-files -s | grep Foo.java <= o See all ways to specify a revision: https://git-scm.com/docs/gitrevisions o Find the ten biggest files in your repo => git ls-tree -r -l --full-name HEAD | sort -n -r -k 4 | head -n 10 <= _ * Setup * __ o Make a bare copy, and add as a new remote so that you can push to it. => cd repo # go to repository git clone --bare `pwd` /backup/repo.git # make bare copy git remote add backup /backup/repo.git # give it a name git push backup # for updates git remote -v # see new remote <= o Add upstream (if doesn't already exist) and track. => git remote add upstream https://github.com/USERNAME/repo.git git branch -u upstream/master master <= o Change an existing origin or upstream, and track master. => git remote set-url origin $HOME/Dropbox/git/repo.git git branch -u origin/master master git remote set-url upstream /path/repo.git git branch -u upstream/master master <= o Set an upstream for current branch the first time you push => git push -u origin [current_branch] <= o Improve performance on NFS: => git config core.preloadindex true <= o Mirror a repo: => git clone --mirror repo_url git fetch --all # to update <= o For better diffs by default: => git config --global diff.algorithm patience <= _ * Fixing stuff * __ o Redo the last commit, before having pushed => git commit -m "Bad commit" git reset HEAD~ # keeps changes as uncommited, unless --hard [edits] git remove [stuff] git add [stuff] git commit -c ORIG_HEAD # Reuses previous commit message; otherwise git commit # Make new commit message <= o Edit commit message after commiting and before pushing. => git commit --amend <= o Undo a merge. (Try to avoid using --hard for any resets.) => git reset --merge ORIG_HEAD <= o Revert a pushed commit. => git revert 123ab... git commit <= o To revert just some files in a pushed merge. => git revert --no-commit 123ab... git reset git add path/file.txt path/directory/ git commit git reset --hard <= o Remove a directory from git without affecting local working copy. => git rm --cached -r some_directory/ <= o To undo all commits and edits that have not yet been pushed to the origin. This is like deleting your working copy and checking out again. => git reset --hard origin/master <= o Make a detached HEAD point to master You have done ``git checkout rev'' to look at a revision at some point, so HEAD now points somewhere different from master (or your current branch). You want to point HEAD back to master. => $ git checkout master $ git log --decorate --oneline a047b24 (HEAD -> master) later revision ... <= If you have any changes to save, then first stash them, and apply later. Otherwise, you will be obliged to destroy them with ``git checkout -f''. o Making master point to a detached HEAD. You have done ``git checkout rev'' to look at a revision at some point, so HEAD now points somewhere different from master (or your current branch). You want to move master to where HEAD currently is. If you have any changes to save, then stash them, and apply later. Otherwise, you will be obliged to destroy them with ``git checkout -f'' and ``git reset --hard''. In this case the HEAD points to a later revision than master: => $ git log --decorate --oneline a047b24 (HEAD) later revision 6e0bc6b (master) earlier revision <= First, make the HEAD point to master => $ git checkout master $ git log --decorate --oneline 6e0bc6b (HEAD -> master) earlier revision <= Next move both back to the later revision => $ git reset a047b24 $ git log --decorate --oneline a047b24 (HEAD -> master) later revision 6e0bc6b earlier revision <= Let's begin again with a detached HEAD at an earlier revision, so master is not visible: => $ git log --decorate --oneline 6e0bc6b (HEAD) earlier revision <= First, make the HEAD point to master => $ git checkout master $ git log --decorate --oneline a047b24 (HEAD -> master) later revision 6e0bc6b earlier revision <= Now you can move both back to where HEAD used to be => $ git reset 6e0bc6b $ git log --decorate --oneline 6e0bc6b (HEAD -> master) earlier revision <= o Get file contents at a particular revision. You want to get some files as they looked after a particular commit, but the commit may not have directly affected those files. First you find the commit hash you want with => git log --stat <= and you find a commit ``4e7e2793026f'' on November 17, a moment at which you liked a particular file, even though that commit did not change that file. You can cat the contents of a file ``FT.java'' at that revision two ways => git show 4e7e2793026f:./FT.java git cat-file -p 4e7e2793026f:./FT.java <= Use full paths, or use a dot for a path relative to the current directory. To find the hash of the blob at that particular moment => $ git ls-tree -r 4e7e2793026f | grep FT.java 100644 blob 23df3f17a4af6cc9a55907cc9273729911193b97 FT.java <= To cat the contents of that file blob: => git show 23df3f17a4af6 git cat-file -p 23df3f17a4af6 <= o List all references: => git show-ref <= o Change the active branch on a bare repository => git symbolic-ref HEAD git symbolic-ref HEAD refs/heads/mybranch <= o Delete a file from history (read about BFG elsewhere): => git clone /foo.git cd foo/ java --jar bfg.jar -D big_ugly_file.ppt git reflog expire --expire=now --all && git gc --prune=now <= _ * Branches * __ o Make a new branch and preserve local changes without changing master. Then commit and push to origin. Compare to master. => git checkout -b new_branch_name git commit -a git push --set-upstream origin new_branch_name git diff master..new_branch_name <= o Remove a branch, locally and remotely => git branch -d branchname git push origin --delete branchname <= o Remove local references to remote branches that no longer exist: => git branch -a -v git remote -v git remote prune origin for b in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D "$b" ; done <= o Track all remote branches => B=`git branch --list | grep '^[*]' | sed 's/^[*] //' ` git remote prune origin git fetch -p --all git branch -r | grep origin/ | grep -v '\->' | while read remote; do b="${remote#origin/}" if ! git rev-parse --verify "$b" > /dev/null 2>&1 ; then git branch --track "$b" "$remote" else git checkout $b git pull git checkout $B fi done git fetch -p --all for b in `git branch -vv | grep ': gone]' | awk '{print $1}'`; do git branch -D "$b" ; done git pull --all git branch -vv --all <= o Compare a file in two different branches: => git diff -b otherbranch myfile # compare to HEAD git diff -b branch1 branch2 myfile git diff -b branch1..branch2 myfile <= o Recover a local branch that you deleted too soon. => $ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'. $ git branch -d foo Deleted branch foo (was 5698004). $ git reflog | head 51c4772 HEAD@{0}: checkout: moving from foo to master 5698004 HEAD@{1}: checkout: moving from master to foo $ git branch foorestored 5698004 <= o Merge specific file from another branch Here are two ways to do it. => git checkout master git checkout other_branch -- relative/path/to/foo.txt # [1] git show other_branch:absolute/path/to/foo.txt > absolute/path/to/foo.txt # [2] <= _ * Making a Subversion working copy into a Git respository * First check out a working copy of Subversion, and create a new git repository that shares the working copy: => svn co URL/trunk svnGitRepo cd svnGitRepo git init cat > .gitignore <<EOF .svn/ EOF git add . git status git commit -m "imported from svn" git log <= Then I can make a copy of this repository to a detachable disk. => cd /media/USBDISK git clone /path/svnGitRepo gitOnly # locally <= Here's a sample remote path: => git clone ssh://host/~/path/svnGitRepo gitOnly # remote <= Assume that the git-only copy is modified offsite. => cd /media/USBDISK/gitOnly echo foo > testfile git add testfile git commit -m test git log <= Later that detachable disk is reconnected and you want the changes merged with the latest version of the SVN repository. First update the original SVN working copy, and save the changes into that Git repository. => cd $HOME/svnGitRepo svn up git commit -m "updated from SVN" <= Thet get the updates from the offsite copy and check them into SVN. => cd $HOME/svnGitRepo git pull /media/USBDISK/gitOnly svn commit -m "updated from Git" <= Then merge those SVN changes into the offsite Git copy: => cd /media/USBDISK/gitOnly git pull <= If the automatic merge fails, then edit the file however you want. Then, add the conflicted file again, to stage it for commitment: => git add path/to/merged_file git commit -m "merged SVN updates" <= You can also ``push'' commited changes from the client back to the original repository, but I discourage it. Your changes will not immediately appear in the original working copy files. Bill Harlan, 2009-2016