Git notes

From raju

Contents

workflow

Updating feature branch with the latest development branch

tags | bring feature branch up to date with development branch

Situation 1:

  • User 1 raised a merge request to merge feature1 to development branch
  • Before the merge request is accepted, development branch is updated by User 2

Situation 2:

  • Say you forked from development branch a while ago to work on a feature and created a branch called "feature1".
  • After a while, development branch might have progressed and may have new changes added to it.

Task:

  • Bring the feature1 branch up to date with the latest development branch.

Solution:

Get the latest versions of development and feature branches in the local repository.

    git checkout development
    git pull
    git checkout feature1
    git pull
    

Merge development branch into the feature branch and resolve any conflicts that may arise.

    git merge development
    

Push the changes to the remote.

    git push
    

Note:- The "git merge development" command works even if you have local changes not committed to feature1.

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
    

git grep related

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

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
    

Ref:- https://stackoverflow.com/questions/10868591/how-to-git-grep-in-the-whole-tree-when-im-in-a-subdirectory


Tips

frequently used

    git pull --rebase --autostash -v origin
    

git pull autostash

    git pull --rebase --autostash
    

The --autostash works only with --rebase. It was introduced in git 2.6 (2015-09-28).

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

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

viewing diffs

merge a development branch into master

gitlab

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 related

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.

Commits related

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

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:

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 cherry-pick

    git cherry-pick <Commit1> <Commit2> <...>
    

Ref:-

git log

Check commits between two branches

    git log branch1..branch2
    

tags | show commits between two branches

branches related

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.

Configuration related

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

where to put git ignore file

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

It is a very good book and is my go to reference on git.