Git notes
From raju
workflow
Updating feature branch with the latest development branch
rebase to another branch
To take BranchB and rebase it on top of BranchA
1) Update BranchA to the latest version if needed
git checkout BranchA git pull --rebase --autostash -v origin
2) Merge changes from BranchA into BranchB
git checkout BranchB git rebase --autostash -v BranchA
This effectively makes BranchB look as if it was branched off of BranchA.
You can also use 'git merge' instead of rebase but that will create a merge commit.
git checkout BranchB git merge BranchA
find files containing two words
tags | multiple words
git grep --all-match -e word1 -e word2
will search for all files that contain both the words somewhere in the file (not necessarily on the same line).
In general
git grep --all-match -e <regex1> -e <regex2>
Ref:-
- http://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja/ - talks about many other use cases of "git grep"
- https://git-scm.com/docs/git-grep - documentation on "git grep"
search from project root
tags | git grep
Solution 1:
git grep pattern -- :/
Solution 2: The git aliases that run shell commands are always executed in the top level directory. So add this to your .gitconfig file:
[alias] # rgrep stands for repo grep rgrep = !git grep
Tips
git pull autostash
git pull --rebase --autostash
The --autostash works only with --rebase. It was introduced in git 2.6 (2015-09-28).
- Explained very well in https://cscheng.info/2017/01/26/git-tip-autostash-with-git-pull-rebase.html
- documentation - https://git-scm.com/docs/git-pull#git-pull---autostash
rebasing using git gui
Q. How to do git pull --rebase using git gui?
A. The trick is to add a custom command in git gui:
Tools -> Add Name: Pull with Rebase Command: git pull --rebase origin Add globally -> check Add
The new command will appear under Tools menu.
Generate diff with no context
git diff -U0
In general, to generate a diff with <n> lines of context, use
git diff -U<n>
or
git diff --unified=<n>
The default is 3 lines of context.
Get current branch name
Git >= 2.22
git branch --show-current
Git >= 1.7
git rev-parse --abbrev-ref HEAD
Git >= 1.8
git symbolic-ref --short HEAD
Other approaches
git branch | grep \* | cut -d ' ' -f2 git branch | sed -n '/\* /s///p'
Ref:- https://stackoverflow.com/questions/6245570/how-to-get-the-current-branch-name-in-git
show modified files in the current directory only
git status .
or more generally
git status /path/to/dir
works from git 1.7 onwards. Does not work with git 1.6.
multiple repositories
The mr tool in myrepos is very handy when working with multiple git repositories. See http://myrepos.branchable.com/ for more details.
Author of myrepos - Joey Hess. His contact info is at https://joeyh.name/contact/
Diff word by word
To diff word by word
git diff --color-words
To set up an alias for it
git config --global alias.wdiff "diff --color-words"
which will add the following lines to ~/.gitconfig
[alias] wdiff = diff --color-words
Once done, "git wdiff" will do the same thing as "git diff --color-words"
delete branches
To delete a remote branch
git push <remote_name> -d <branch_name>
To delete a local branch
git branch -d <branch_name>
Ref:-
- https://www.git-tower.com/learn/git/faq/delete-remote-branch
- https://stackoverflow.com/questions/2003505/how-do-i-delete-a-git-branch-both-locally-and-remotely
Migrate from sourceforge to github
The instructions to move a git repository from sourceforge to github are clearly laid out in https://help.github.com/articles/importing-a-git-repository-using-the-command-line/ .
In particular, to migrate the sampleusage project from sourceforge to github, I did
Login into github website create a new repository called sampleusage: https://github.com/KamarajuKusumanchi/sampleusage git clone --bare ssh://kamaraju@git.code.sf.net/p/sampleusage/git sampleusage-git cd sampleusage-git git push --mirror https://github.com/KamarajuKusumanchi/sampleusage.git cd .. rm -rf sampleusage-git
To get a local copy
git clone git@github.com:KamarajuKusumanchi/sampleusage.git cd sampleusage git config user.name "Kamaraju S. Kusumanchi" git config user.email "kamaraju@gmail.com"
Sample work flow once it is all done
git add dummy_file git commit -m "dummy commit message" git push -u origin master
After making sure that everything on github is working properly, I submitted a ticket to delete the original sourceforge project.
git and vimdiff
- http://usevim.com/2012/03/21/git-and-vimdiff/ - contains tips on how to effectively use git, vimdiff and vim together.
viewing diffs
- http://365git.tumblr.com/post/474079664/whats-the-difference-part-1 - explains how to diff between HEAD, Index and Working tree
merge a development branch into master
gitlab
- pricing - https://about.gitlab.com/gitlab-com/
- explore project - https://gitlab.com/explore
- compare terminology across different platforms - https://about.gitlab.com/2016/01/27/comparing-terms-gitlab-github-bitbucket/
pruning
To list the branches that are merged into master
git branch --merged master
To list the branches that are merged into HEAD (i.e. tip of the current branch)
git branch --merged
To list the branches that were not merged
git branch --no-merged
By default this only applies to local branches. Use -a to show both local and remote branches; -r to show only remote branches.
To delete all local branches that have been merged into master
git branch --merged | grep -v '\* master' | xargs -n1 git branch -d
To delete all local branches that have been merged into the current branch
git branch --merged | grep -v '^\*' | xargs -n1 git branch -d
what files changed between two branches
To compare the current branch against master
$ git diff --name-status master
To compare any pair of branches
$ git diff --name-status firstbranch..secondbranch
time zone of the committer
git cat-file -p <commit-id>
Will show the entire commit object. It will contain two lines like this:
author Foo Bar <foo@bar.com> 1398017575 -0400 committer Foo Bar <foo@bar.com> 1398017575 -0400
As you can see, the timezone info follows the Unix-epoch timestamps.
Note that the timezone is something set by the user himself on the client. So it can be easily spoofed by the user if he desires to.
list of commits from an author
git log --author=bob git log --author=foo@bar.com
checkout a file with a hash
git checkout [hash] -- [file]
Ref:- https://stackoverflow.com/questions/215718/how-can-i-reset-or-revert-a-file-to-a-specific-revision
external links
- [1] - Combine two files into one while preserving line history in git
- [2] - Explains how to work with git submodules. Easy to read, contains example.
- A few git tips you didn't know about
- [3] - The section on commit message templates is pretty interesting.
git diff only list filenames
git diff --name-status otherbranch
Related commands:
git diff --name-status [SHA1 [SHA2]] git diff --name-status mybranch..otherbranch git diff --name-only SHA1 SHA2 git diff --name-only HEAD~10 HEAD~5 git log --name-status --oneline [SHA1..SHA2] git diff --stat HEAD~5 HEAD git diff --numstat HEAD~5 HEAD
Ref:- https://stackoverflow.com/questions/1552340/how-to-list-only-the-file-names-that-changed-between-two-commits - contains many other commands that are slightly different to do slightly different things.
what changed in a commit
git diff COMMIT^!
which is a shortcut for
git diff COMMIT~ COMMIT
Ref:- https://stackoverflow.com/questions/17563726/how-to-see-the-changes-in-a-git-commit
git diff N last commits
git diff HEAD~N
number of commits
To get a commit count for a revision (HEAD, master, a commit hash):
git rev-list --count <revision>
To get the commit count across all branches:
git rev-list --count --all
Ref :- https://stackoverflow.com/questions/677436/how-to-get-the-git-commit-count
check commits where a file has changed
tags | show commits on a single file
To list the last 3 commits that changed a file
git log -n3 --follow -- filename
Ref:- https://stackoverflow.com/questions/3701404/list-all-commits-for-a-specific-file
Change last commit message
git commit --amend
Add a file to the last commit
git add missed-file.txt git commit --amend
Remove a file that was accidentally committed
- See point (3) in https://about.gitlab.com/2018/08/08/git-happens/ which uses "git reset" to do this.
Tasks
discard all changes in working directory
git checkout -- .
Notes: It will not remove the untracked files.
discard last commit
git reset --hard HEAD~1
See also: https://stackoverflow.com/a/6866485/6305733
update all repositories in a directory
My way:
Download the following scripts:
- update_git_repos.sh - https://github.com/KamarajuKusumanchi/rutils/blob/master/bin/update_git_repos.sh
- git_shelf.sh - https://github.com/KamarajuKusumanchi/rutils/blob/master/bin/git_shelf.sh
- git-up - https://github.com/KamarajuKusumanchi/rutils/blob/master/bin/git-up
and put them in a directory where the shell can find them. Then run
update_git_repos.sh /path/to/dir
It works by calling git_shelf.sh which applies a given "git operation" on all the git repos under a directory. In this case, it is invoked as
git_shelf.sh /path/to/dir up
so it calls "git up" on all directories under /path/to/dir.
Since there is no standard "git up" command, it calls the git-up script.
A barebones solution would look like
for i in *; do echo $i; if [ -d "$i" ]; then cd $i; git up; cd ..; fi done
But the git_shelf.sh approach is better as it generalizes for any git operation. For example to search all git repos that have the word foo and bar, I use
git_shelf.sh /path/to/dir grep -i --all-match -e foo -e bar
or more simply
grep_git_repos.sh /path/to/dir -i --all-match -e foo -e bar
where grep_git_repos.sh is https://github.com/KamarajuKusumanchi/rutils/blob/master/bin/grep_git_repos.sh
checkout previous N versions of a file
https://github.com/KamarajuKusumanchi/rutils/blob/master/bin/xtract_hist_git
/* Todo:- Migrate contents of https://malayamaarutham.blogspot.com/2011/08/extract-historical-versions-of-file.html to this wiki and delete that blog post */
git commands usage
git stash
git stash drop - Remove a single stash.
git stash clear - Remove all the stash entries.
Documentation - https://git-scm.com/docs/git-stash
git log
Check commits between two branches
git log branch1..branch2
tags | show commits between two branches
rename a branch locally and remotely
git checkout <old_name> git branch -m <new_name> git push origin -u <new_name> git push origin --delete <old_name>
Ref:- https://linuxize.com/post/how-to-rename-local-and-remote-git-branch/
rename a local branch
To rename the current branch
git branch -m <newname>
To rename a branch while in another branch
git branch -m <oldname> <newname>
By default when you push the new branch to the remote, it will add it as a new branch and will not delete the old branch. See https://stackoverflow.com/questions/6591213/how-do-i-rename-a-local-git-branch if you want to rename the branch on the remote while doing the push.
Configure http proxy
git config --global http.proxy http://login:password@your.proxy.server:port
git config settings
To check which config comes from which file
git config --list --show-origin
Related commands
git config --system -l
tags | where is a setting coming from
cache username and passwords
Git credential storage for Windows:
- wincred
- Git's built-in credential storage for Windows.
- provides single-factor authentication support working on any HTTP enabled git repository.
git config --global credential.helper wincred
- manager
- Provided by the Git Credential Manager for Windows (GCM)
- provides multi-factor authentication support for Azure DevOps, Team Foundation Server, GitHub, and Bitbucket.
git config --global credential.helper manager
- Project website: https://github.com/Microsoft/Git-Credential-Manager-for-Windows
- winstore
- no longer maintained; Use GCM instead.
- succeeded by GCM
- Windows Credential Store for Git
- git-credentials-winstore
- Project website: https://gitcredentialstore.codeplex.com/
default location of global git ignore file
Linux:
$HOME/.config/git/ignore
Windows:
%USERPROFILE%\git\ignore
Patterns which a user wants Git to ignore in all situations (e.g., backup or temporary files generated by the user’s editor of choice) generally go into a file specified by core.excludesFile in the user’s ~/.gitconfig. Its default value is $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore is used instead.
Ref:-
- https://git-scm.com/docs/gitignore#_description
- https://stackoverflow.com/questions/7335420/global-git-ignore
where to put git ignore file
- https://help.github.com/articles/ignoring-files/ - very well explained, brief and to the point.
dummy
git bash
To download git bash, use either https://gitforwindows.org/ or https://git-scm.com/downloads
"Git for Windows" used to be developed using the development environment called "msysGit", but roughly coinciding with Git 2.1, msysGit was superseded by a new development environment.
Ref:- https://github.com/git-for-windows/git/wiki/FAQ -> "What is the relationship between Git for Windows and msysGit?"
detaching HEAD
Detaching HEAD just means attaching it to a commit instead of a branch. Say we have this beforehand:
HEAD -> master -> C1
git checkout C1
and now it is
HEAD -> C1
relative refs
- Move upwards one commit at a time with ^
- Move upwards a number of times with ~<num>
branch forcing
git branch -f master HEAD~3
moves (by force) the master branch to three parents behind HEAD.
reversing changes
Two primary ways: git reset, git revert.
Sample command using reset
git reset HEAD~1
Since git reset "rewrites history", you can use it for local branches but not for remote branches.
To reverse changes and share those reversed changes with others, use git revert. For example
git revert HEAD
interactive rebase
Call the rebase command with the -i option. Sample command
git rebase -i HEAD~4
Exclude .git directory from grep searches
exclude .git directory when comparing two repos
diff -rq -x .git repo repo_bkp
ssh key generation
ssh-keygen -t ed25519 -C "email@example.com"
public key will be stored in ~/.ssh/id_ed25519.pub
debug slowness in git bash
$ time echo $(__git_ps1)
commit only some parts of files
Git can stage certain parts of files and not the rest. For example, if you make two changes to a file, you can stage one of them and not the other.
git add --patch
git add -i
Ref:- Pro Git by Scott Chacon and Ben Straub -> Chapter 7. Git Tools -> Interactive Staging
books
- https://openlibrary.org/books/OL27737331M/Pro_Git - Pro Git by Scott Chacon, Ben Straub
It is a very good book and is my go to reference on git.