How to work with git

Issue #531

Expand commits in Sublime Merge

1
2
3
4
{
"expand_merge_commits_by_default": true,
"translate_tabs_to_spaces": true
}

local hooks .git/hooks vs hooksPath

1
git config core.hooksPath ~/.git-templates/hooks

Only hooksPath gets run. Removing hooksPath make local hooks work

https://stackoverflow.com/questions/39332407/git-hooks-applying-git-config-core-hookspath

Use git templates

https://coderwall.com/p/jp7d5q/create-a-global-git-commit-hook

Define alias in zshrc

1
2
3
vim ~/.zshrc
alias check="~/.git-templates/hooks/check.sh"
source ~/.zshrc

pre-commit

https://itnext.io/using-git-hooks-to-enforce-branch-naming-policy-ffd81fa01e5e

1
(feature|fix|refactor)\/[a-z0-9-]+$

How to setup multiple git accounts for GitHub and Bitbucket

Issue #514

Generate SSH keys

1
2
3
4
5
6
7
8
9
ssh-keygen -t rsa -C "onmyway133@gmail.com" -f "id_rsa_github"
ssh-keygen -t rsa -C "onmyway133bitbucket@gmail.com" -f "id_rsa_bitbucket"

pbcopy < ~/.ssh/id_rsa_github.pub
pbcopy < ~/.ssh/id_rsa_bitbucket.pub

ssh-add -D
ssh-add id_rsa_github
ssh-add id_rsa_bitbucket
1
2
3
4
5
6
7
8
9
10
11
12
13
vim ~/.ssh/config

#Github (personal)
Host gh
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_github

#Bitbucket (work)
Host bb
HostName bitbucket.org
User git
IdentityFile ~/.ssh/id_rsa_bitbucket

Config

1
2
git config --global user.email "onmyway133@gmail.com"
git config --local user.email "onmyway133bitbucket@gmail.com"

Read more

Useful git commands for everyday use!

Issue #239

Original post https://medium.com/flawless-app-stories/useful-git-commands-for-everyday-use-e1a4de64037d


Do you know that questions about git get the most views on StackOverflow? I’ve searched a lot on Google how to execute certain actions with git, and this actually slowed me down a lot. There are some actions that we tend to use a lot, so it’s good to learn them. Here are my favorites, learning from friends and internet, hope you find them useful.

Before we begin, you should run git –version to check your current git version, mine is 2.12.2 as in macOS High Sierra. Here is the official git documentation, you can read details about git commands, parameters and new releases of git.

Useful commands

Diff

1
2
git diff feature/my_branch develop > file.diff
git apply file.diff

πŸ” Status

Check the status of working directory and staging area:

git status

Show changes between HEAD and working directory:

git diff

Show the list of commits in one line format:

git log --oneline

Show commits that make add or remove a certain string:

git log -S 'LoginViewController'

Search commits that contain a log message:

git log β€” all β€” grep=’day of week’

πŸ” Tag

List all tags:

git tag

Tag a commit:

git tag -a 1.4 -m "my version 1.4"

Delete remote tags:

git push --delete origin tagname

git push origin :tagname

Push tag to remote:

git push origin tagname

Rename tag:

git tag new old
git tag -d old
git push origin :refs/tags/old
git push --tags

Move tag from one commit to another commit:

git push origin :refs/tags/<tagname>
git tag -fa tagname
git push origin master --tags

πŸ” Remote

List all remote:

git remote

Rename remote:

git remote rename old new

Remove stale remote tracking branches:

git remote prune origin

πŸ” Branch

List all branches:

git branch

Create the branch on your local machine and switch in this branch:

git checkout -b branch_name

Create branch from commit:

git branch branch_name sha1_of_commit

Push the branch to remote:

git push origin branch_name

Rename other branch:

git branch -m old new

Rename current branch:

git branch -m new

Rename remote branch:

git branch -m old new               # Rename branch locally    
git push origin :old                 # Delete the old branch    
git push --set-upstream origin new   # Push the new branch, set local branch to track the new remote

Delete a branch:

git branch -D the_local_branch

git push origin :the_remote_branch

Delete all local branches but master

git branch | grep -v "master" | xargs git branch -D

πŸ” Commit

Undo last commit:

git reset --hard HEAD~1

Squash last n commits into one commit:

git rebase -i HEAD~5

git reset --soft HEAD~5
git add .
git commit -m "Update"
git push -f origin master

Move last commits into new branch:

git branch newbranch
git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work.*1
git checkout newbranch

Make changes to older commit

1
2
3
4
git rebase -i HEAD^^^
// change from pick to edit, then :wq
git add .
git rebase --continue

πŸ” Cherry Pick

Add some commits to the top of the current branch:

git cherry-pick hash_commit_A hash_commit_B

πŸ” Reflog

Show reflog:

git reflog

Get commit:

git reset --hard 0254ea7

git cherry-pick 12944d8

πŸ” Revert

Revert the previous commit:

git revert HEAD
git commit

Revert the changes from previous 3 commits without making commit:

git revert --no-commit HEAD~3..

πŸ” Amend

Amend previous commit:

git commit --amend

git commit --amend --no-edit

git commit --amend -m "New commit message"

Changing git commit message after push:

git commit --amend -m "New commit message"
git push --force <repository> <branch>

πŸ” Checkout

Checkout a tag:

git checkout tagname

git checkout -b newbranchname tagname

Checkout a branch:

git checkout destination_branch

Use -m if there is merge conflict:

git checkout -m master // from feature branch to master

Checkout a commit:

git checkout commit_hash

git checkout -b newbranchname HEAD~4

git checkout -b newbranchname commit_hash

git checkout commit_hash file

Checkout a file:

git checkout c5f567 -- Relative/Path/To/File

πŸ” Stash

Save a change to stash:

git stash save "stash name"

git stash

List all stashes:

git stash list

Apply a stash:

git stash pop

git stash apply

git stash apply stash@{2}

πŸ” Rebase

Rebase the current branch onto master:

git rebase master // rebase the current branch onto master

Continue rebase:

git rebase --continue

Abort rebase:

git rebase --abort

πŸ” .gitignore

Un-track files that have just been declared in .gitignore:

git rm -r --cached .
git add .
git commit -am "Remove ignored files"

πŸ” Index

Remove untracked files:

git clean

Remove file from index:

git reset file

Reset the index to match the most recent commit:

git reset

Reset the index and the working directory to match the most recent commit:

git reset --hard

πŸ” Misc

Get their changes during git rebase:

git checkout --ours foo/bar.java
git add foo/bar.java

Get their changes during git merge:

git pull -X theirs

git checkout --theirs path/to/the/conflicted_file.php

git checkout --theirs .
git add .

git checkout branchA
git merge -X theirs branchB

Merge commits from master into feature branch:

git checkout feature1
git merge --no-ff master

Find bug in commit history in a binary search tree style:

git bisect start

git bisect good

git bisect bad

Git alias

If there are commands that you use a lot, then consider using git alias. This is how to make alias for git status, then you can just type git st:

git config β€” global alias.st status

Alias configurations are stored in .gitconfig file, you can learn some cool aliases from thoughtbot and mathiasbynens.

Delete all local branches except master

1
git config --global alias.dlb '!git branch | grep -v "master" | xargs git branch -D'

Prune upstream branches

1
git config --global alias.pu 'remote prune upstream'

GUI clients

Doing things in command line is cool and faster. However for viewing branches and commits, I find using a GUI client more visualizing and comfortable. You can see a list of all GUI clients here, I myself use SourceTree.

Check before you commit

We usually have some experiment code that we don’t want they to step into our commit. I usually mark my experiment with // but sometimes forget to unstage that.

Starting with 2.9, Git has improvement on its commit hook which makes it globally using hooksPath.

Firstly we nee to create a file called pre-commit, and place it into, for example, /Users/khoa/hooks:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/bin/sh

# https://appventure.me/2016/04/04/prevent-accidental-test-code-commits/

if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# The special marker tag to mark things which we still need to change
marker="<TEST>"

# Redirect output to stderr.
exec 1>&2

if test $(git diff --cached -z $against | grep $marker | wc -c) != 0
then
cat <<\EOF
Error: Still has invalid debug markers in code:
EOF
echo `git diff --cached -z $against -G $marker`
exit 1
fi

In your project, run git config core.hooksPath /Users/khoa/hooks.

Whenever you commit a file with that pattern, it won’t let you commit. For how to make this work in SourceTree, check:
SourceTree and pre commit hook
Pre-commit file works perfectly in terminal, but SourceTree seems to ignore it. I use both terminal and SourceTree, as…medium.com

Where to go from here

This is just scratching the surface of what git can do, if you want to learn more, here are some links to get started.