My personal Git Memo
Here is an unordered list of git commands, configurations, tricks, articles, gotchas that I don’t want to forget.
- Find out all commit hashes of the git submodules your branch is pointing at
- Find commit by message string
- Show all commits from an author, in a specified date range
- Fix
.git/index.lock
error - Permanently remove a file from a repo
- Show branch name in Linux terminal
- Compare a file across 2 branches
- List all commits for a specific file
- Configure git aliases
- Commit only part of a file
- Git hooks
- Discard changes to git submodules
Find out all commit hashes of the git submodules your branch is pointing at
git ls-tree <branch you are currently on>:<path to directory containing the submodules>
Example
git ls-tree master:external
Reference here
Find commit by message string
git log --all --grep="your commit message here (or part of it)"
Use --all
to search across all branches. Don’t use it if you want to restrict the search to the branch you are currently on.
Reference here
Show all commits from an author, in a specified date range
git log --pretty=format:"%ad - %an: %s" --after="2016-01-31" --until="2017-12-01" --author="John Doe"
Fix .git/index.lock
I get this from time to time, and I still haven’t figured out the reason why it occurs.
You just have to remove the index.lock
file (not the index!).
rm .git/index.lock
Reference here
Permanently remove a file from a repo
You should really think twice before performing this operation. Also, keep in mind that this command will override git history.
Anyway, there are some real use cases when this command is useful.
Let’s say that you commit a large file by mistake. You have some stuff to commit and you run a convenient git add .
to stash all your changes. Then you forget to review your changes and those changes end up in the commit history. At this point you are still on a local branch, so you can still save the day by removing the file, stashing your changes once again and running a git commit --amend
. If you realize your mistake some commits later, but you have not yet pushed them, you can also squash your commits. But if you have already pushed to your remote repository you are out of luck, and that’s when this command could help you.
Let’s suppose that at some point in time you created a README.md
for your project, but for some esoteric reason you want to remove it from your project. You can permanently remove your README.md
file and make it disappear from your git history with the following command.
git filter-branch --tree-filter 'rm -rf README.md' HEAD
If you now run git status
, you will notice that your local branch and your remote branch differ. That’s because your remote branch still has a README.md
in its history.
jack@ThinkJack:~/Repos/d3-visualizations(master)$ git status
On branch master
Your branch and 'origin/master' have diverged,
and have 26 and 26 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Now you have to push your changes to the remote repo. You have to use --force
, since this is not a fast-forward commit and you have to rewrite the history of the remote repo.
git push origin master --force
Reference here
Show branch name in Linux terminal
For this, you have to edit your .bashrc
file. It should be in your home
directory.
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\]$(parse_git_branch)\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(parse_git_branch)\$ '
fi
unset color_prompt force_color_prompt
Reference here
Compare a file across 2 branches
git difftool <target branch> -- <your file>
For example, if you are on master
and want to check a file on your release-01.03.02
branch, run:
git difftool release-01.03.02 -- src/js/index.js
Reference here, and if your file has a different name in 2 different branches, see here.
List all commits for a specific file
git log --follow filename
Reference here
Configure Git aliases
You can use git config
to create your aliases, but there is a faster way.
Add (or edit) the alias
section of your .gitconfig
file. It should be in your home
directory.
These is the alias
section in my .gitconfig
.
[alias]
st = status
au = add -u
dt = difftool
cm = commit -m
cma = commit --amend --no-edit
co = checkout
# list aliases https://gist.github.com/mwhite/6887990
la = "!git config -l | grep alias | cut -c 7-"
For some other Git aliases, see this wiki.
Commit only part of a file
You can use git gui
for this. If you don’t have it already, install it with sudo apt-get install git-gui
. Here is what I usually do:
git gui
- right click on the code you want to commit and select
stage lines for commit
(orstage hunk for commit
) git stash
, to save in the stash all changes that I am not committing right nowgit commit
git stash apply
git stash drop
If you like (I personally don’t), you can replace
git stash apply
git stash drop
with
git stash pop
Reference here.
In alternative to git gui
, you can use interactive staging from the terminal. I have never tried this.
Git hooks
I am not an expert on hooks in Git, but I found this really nice article about them.
I think the most useful hooks are
- pre-push
- prepare-commit-msg
- post-commit
It would be nice to have a pre-merge hook, so we could prevent a feature branch from merging into master if certain conditions are not met (e.g. your tests fail). Since a pre-merge hook is not available, you’ll have to [write it]((https://stackoverflow.com/questions/19102714/how-would-i-write-a-pre-merge-hook-in-git).
Reference here.
Discard changes to Git submodules
I think it happened only once to me, but I had to reset all submodules with this line:
git submodule foreach git reset --hard
Reference here.