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 (from

    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
  • 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

    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

    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
    for tag in `git branch -r | grep "tags/" | sed 's/ tags\///'`; do
      git tag -a -m"Converting SVN tags" $tag refs/remotes/$tag
    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 new CVSROOT first needs to be created next to the module subdirectories, e.g. with cvs -d . init. The following assumes the current working directory to be on the same level where CVSROOT 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
René Mayrhofer
Professor of Networks and Security & Director of Engineering at Android Platform Security; pacifist, privacy fan, recovering hypocrite; generally here to question and learn