Git Cheat Sheet
Git commands that are not intuitively found:
-
git log --graph --all --oneline --reflog
saves the day then the HEAD reference is lost in a weird merge (e.g. when a submodule wasn’t pushed but the enclosing repo was). -
Removing a subtree from a repository including all of its history (e.g. when non-open-source files were committed to a repository before pushing the repo to an external server or to remove old directories after splitting a repo):
git filter-branch --index-filter "git rm -r -f --cached --ignore-unmatch <DIRECTORY TO REMOVE>" --prune-empty HEAD
-
Removing everything besides a specific directory and tracking its history even through renames and copies (NEW RECOMMENDED VERSION, but requires package
git-filter-repo
to be installed):git filter-repo --subdirectory-filter <DIRECTORY TO KEEP>
-
(DEPRECATED) Removing everything besides a specific directory (from http://stackoverflow.com/questions/359424/detach-subdirectory-into-separate-git-repository):
git clone --no-hardlinks XYZ ABC cd ABC git filter-branch --subdirectory-filter ABC -- --all git reset --hard # and now really, really clean up all objects not referenced anymore... git remote rm origin git update-ref -d refs/original/refs/heads/master git reflog expire --expire=now --all git repack -ad git clean -d -f git gc --aggressive git prune # instead of the above, the following might reclaim more space, a lot quicker: cd ..; mkdir ABC-min.git; cd ABC-min.git git init --bare cd ../ABC git push ../ABC-min.git HEAD
-
(DEPRECATED) Removing everything besides a list of files and directories and tracking their history even through renames and copies, which the above method doesn’t track (from http://stackoverflow.com/questions/5998987/splitting-a-set-of-files-within-a-git-repo-into-their-own-repository-preserving):
git clone --no-hardlinks XYZ ABC cd ABC git filter-branch --prune-empty --index-filter 'git ls-tree -z -r --name-only --full-tree $GIT_COMMIT \ | grep -z -iv "filename1" | grep -z -iv "filename2" | grep -z -iv "directory-regex1" | grep -z -iv "directory-regex2" | ... \ | grep -z -v "^git-changelog" | xargs -0 -r -d git rm --cached -r' -- --all # same as above with git init/push to reclaim space
-
Merging a previously separate (typically small) repository (let’s call it rep1) into an existing (typically larger) repository (let’s call it rep2) under a new path (let’s call it rep1path), keeping history:
cd rep1 mkdir -p rep1path git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} rep1path git commit -m "Move to new path in preparation of merge into rep2" [git push] - optional if not working with local repos but going through remote cd rep2 git remote add oldrep1 URL-to-rep1 git fetch oldrep1 git merge oldrep1/master git remote remove oldrep1
-
Importing from subversion (from http://www.sailmaker.co.uk/blog/2013/05/05/migrating-from-svn-to-git-preserving-branches-and-tags-3/):
mkdir newgitrep cd newgitrep git svn init URL-to-svn-rep --stdlayout --prefix=svn/ [this will prefix the branch names with svn/ to make it clear that they were imported] git svn fetch [this will take some time] for branch in `git branch -r | grep "svn/" | grep -v "svn/tags" | sed 's/ branches\///'`; do git branch $branch refs/remotes/$branch done for tag in `git branch -r | grep "tags/" | sed 's/ tags\///'`; do git tag -a -m"Converting SVN tags" $tag refs/remotes/$tag done git remote add oriting new-remote-git-repo-URL git push --all origin git push --tags origin
-
Importing from CVS: Note: If only the
,v
files are available (i.e. the CVS modules), a newCVSROOT
first needs to be created next to the module subdirectories, e.g. withcvs -d . init
. The following assumes the current working directory to be on the same level whereCVSROOT
directory and the module directory (e.g.ABC
, containing the,v
files) are.cvs2git --blobfile="blob.dat" --dumpfile="dump.dat" --username="YOUR NAME <YOUR@EMAIL>" --fallback-encoding utf8 ABC mkdir ABC.git cd ABC.git cat ../blob.dat ../dump.dat | git fast-import