Skip to content
Thach Hoang edited this page Dec 18, 2018 · 23 revisions

Writing commit messages:

How to undo (almost) anything with Git.

Useful commands

Log

Log with committer name and date:

git log --pretty=fuller

Log with full diff:

git log -p

List ignored files:

git ls-files --others -i --exclude-standard

Search the logs:

git log --grep=<pattern>

Tag

Delete remote tags:

git push --delete origin tagname

Fix broken ref

warning: ignoring broken ref refs/remotes/origin/HEAD

This could happen when you delete a default branch:

git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/master
# Optional cleanup
git fetch -p
git gc

Locate commit

git tag --contains <commit>
git branch --contains <commmit> # local
git branch -r --contains <commmit> # remote
git branch -a --contains <commmit> # both

Find the commit that deletes a file:

git rev-list -n 1 HEAD -- <full file path>

String replacement

Search for a string:

git log -S"secret password" -p

Remove a stupid string from history:

git filter-branch -f --tree-filter "find . -name '*.md' -exec sed -i -e 's/secret password/dummy password/g' {} \;"

Time travel

Reset timestamp on last commit, so nobody knows that you're working at 2am:

git amend --no-edit --date='now()'
git amend --no-edit --date='-2 hour' # lol

Plagiarism

Reset author on everything:

git rebase -i --root --exec "git commit --amend --reset-author --no-edit"

But then we lose author dates. Reset them to commit dates:

git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; export GIT_COMMITTER_DATE'

It's possible to set author name/email without affecting dates:

git filter-branch --env-filter 'GIT_AUTHOR_EMAIL=$GIT_COMMITTER_EMAIL; export GIT_AUTHOR_EMAIL'
git filter-branch --env-filter "GIT_AUTHOR_NAME='X'; GIT_AUTHOR_EMAIL='X' GIT_COMMITTER_NAME='X'; GIT_COMMITTER_EMAIL='X';" HEAD

Regret

Undo the last rebase/merge:

git reset --hard ORIG_HEAD

Undo a rebase/merge before that:

git reflog
git log head@{61}
git reset --hard head@{61}

Movers and shakers

Move all files of a repository into a sub-folder.

git filter-branch --prune-empty --tree-filter '
  # dir exists?
  if [[ ! -e "sub-dir" ]]; then
    mkdir -p "sub-dir"
    git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files "sub-dir"
  fi'

Same command on one line:

git filter-branch --prune-empty --tree-filter 'if [[ ! -e "sub-dir" ]]; then mkdir -p "sub-dir"; git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files "sub-dir"; fi'

To rewrite the repository to look as if foodir/ had been its project root, and discard all other history:

git filter-branch --subdirectory-filter foodir -- --all

Pull from another local repo:

git remote add proj-1 ../proj-1
git pull proj-1

Clone this wiki locally