In git there is three essential entity: blob, tree object and commit.
To throw away local changes exits couple of similar commands
git reset --hard
git checkout -f <branch>
Note: Untracked files will be untouched. The <branch>
is optional and if we specified the HEAD it's unnecessary, because by default it's reference to the currently checked out commit.
git clean -dn
this will show you which files or directories are going to be removed without actually removing them
To remove all untracked files
git clean -dfx
Note: -f(force removal), -d(directories), -x(don't use the standard ignore rules from .gitignore and $GIT_DIR/info/exclude
This commands works in conjuction
git reset --hard && git clean -dfx
Note: Removes all modified and untracked files
To restore older state of specific branch use git reset --hard <commit>
. If you want to cancel last resetting use commit hash from link. This hash stores in file .git/ORIG_HEAD
. The full command git reset --hard ORIG_HEAD
Checkout to previous commit state, but save all files in working directory and index
git reset --soft @~2
To cancel last action
git reset --soft ORIG_HEAD
To save message from last commit use one of the following command
git commit -c ORIG_HEAD
opens editor with prefilled commit message
git commit -C ORIG_HEAD
skip the step of opening editor(like git commit -m
)
git commit --amend
combine two steps: git reset --soft
and git commit -c ORIG_HEAD
git commit --amend --no-edit
use the selected commit message without launching an editor
By default git uses git reset --mixed
or short version git reset
. In mixed mode, all files that was added to index removed from there and stay in working directory. The following table show difference between 3 type of mode. The yes
means removed from index or working directory and no
means the opposite.
--hard | --mixed | --soft | --keep | --merge | |
---|---|---|---|---|---|
working directory | yes | yes | no | no | no |
index | yes | no | no | yes | yes |
In addition, the git reset --mixed <commit hash> <path to file>
allows set the path to file to reset to state of commit where that file was.
Note: git reset --keep
resets index entries and updates files in the working tree that are different between and HEAD. If a file that is different between and HEAD has local changes, reset is aborted.
Note: git reset --merge
resets the index and updates the files in the working tree that are different between and HEAD, but keeps those which are different between the index and working tree (i.e. which have changes which have not been added). If a file that is different between and the index has unstaged changes, reset is aborted.
Note: git reset
should generally be considered a 'local' undo method. The preferred method of undoing shared history is git revert
. A revert is safer than a reset because it will not remove any commits from a shared history. A revert will retain the commits you want to undo and create a new commit that inverts the undesired commit. This method is safer for shared remote collaboration because a remote developer can then pull the branch and receive the new revert commit which undoes the undesired commit.
git revert HEAD
create a new commit with the inverse of the last commit. This adds a new commit to the current branch.
Note: Diff between reset
and checkout
is git reset
moves both the HEAD
and branch refs to the specified commit, but git checkout
moves only HEAD
Go back couple commits ago of branch
git branch -f master <hash or branch>
git checkout -B master <hash of branch>
Note: First command set ref to new commit without switching to specified branch. The second one do all the first and switch it.
git branch --merged
show merged branches
git branch --no-merged
show branches that not yet merged
Rename local branch name
git branch -m new-name
If you on different branch
git branch -m old-name new-name
To get previous version only specific file use the following commands
git checkout <hash> <path>
Note: Checking out an old file add file both to working directory and index and does not move the HEAD
pointer. It remains on the same branch and same commit, avoiding a 'detached head' state.
Reset to HEAD state
git checkout HEAD <path>
if the file was on index
git checkout <path>
if the file was on working directory
git merge
consists of 3 parts: base(common ancestor) + our changes + their changes
To find common ancestor between two branches run git merge-base <branch1> <branch2>
. When we start merging git creates MERGE_HEAD
file which contains the commit which we are merging into to current branch. For example, we are on master
branch and git merge fix
add last ref to last commit hash of fix
branch into MERGE_HEAD
file. After successful merging this file will be deleted.
In process of merging conflict we can choose thoose changes are choose. For this case git checkout --ours <file>
take our changes from branch where we stay right now. git checkout --theirs <file>
will take change from branch that merging. To restore state before choosing git checkout --merge <file>
To show 3 way merge diff(base + ours + theirs) changes git checkout --conflict=diff3 --merge <file>
. After merging in index we have 3 simultaneously changes of same file. And it's mean that we can't just run git commit
because we have an unmerged changes and to commit we first need add files to index.
git show :1:<file>
show base version of file
git show :2:<file>
changes in branch where we currently is
git show :3:<file>
changes in branch that we merged
git reset --merge
or git merge --abort
undo the merging. The second one it's a alias of the first command.
To show diff between merged and one of two or n-th parent of merged commit, we can use ^
.
git diff @^1
show the first parent of 3-way merge(current branch where we stay)
git diff @^2
show the second parent of 3-way merge(merging branch)
Carats(^
) and tildes(~
) are relative commit markers in Git. They both mean "parent" but in a different way.
Most commonly used, they are the same. HEAD^1
(or HEAD^
for short) is the same as HEAD
. Always.
The difference comes when they stack. So HEAD^2
means "The second parent of HEAD". This only means anything if there's been a merge. In a merge, the main branch is parent #1; the merged in branch is parent 2. So, HEAD^2 will be the merged parent, whereas HEAD^1 will be the parent merged into.
Here diagram that show diff between ^
and ~
Sometimes merging not going well. Everything merged without conflicts, but we have semantic issue. For example, we've changed declaration of function and in other place where we call this function we've changed that call too. And your teammate create another branch, where he used older version of that function. When it's time, we merge both changes and in our files we have two version of calling function and git merging went well. If we want change older calling function to new, we need to add yet another commit. But we won't leave in our branch commits, that has conflicts. For that case, we have git merge --no-commit
which do merging, but not run automatically commit. We do changes in our conflict files and add to index and after run git commit
or git merge --continue
(both commands do the same operation - run commit).
When we do fast-forward merging it's hard to determine which changes belongs to that branch. The history is straight and log doesn't help us. We can use explicit merge git merge --no-ff <branch>
that disable fast-forward merge algorithm.
git merge --squash <branch>
takes all commits from <branch>
and squash them into one commit and merge it with current branch.
Note: The MERGE_HEAD
file doesn't created. Because in squashing we have only one parent.
There are many merge strategies. By default Git uses recursive strategy.
- recursive
- ours
- theirs
- renormalize
- ignore-all-spaces
- no-renames
- find-renames=n
- subtree=path
- octopus
- ours
- resolve
- subtree
There is important distinction between strategy ours
and option ours
of recursive strategy.
git merge -s ours <branch>
ignores all changes made from other branches
git merge -Xours <branch>
include all changes that will not cause a conflict and in conflict files take our version
git merge -Xtheirs <branch>
include all changes that will not cause a conflict and in conflict files take their version
We can merge multiple branches at once using git merge feature fix
. In this case will be applied octopus
strategy
git cherry-pick <hash>
copy single commit
git cherry-pick master..feature
copy all commits that are in feature
and not in master
In process of cherry picking we can have conflicts and we have 3 options to resolve them:
git cherry-pick --continue
can be used to continue after resolving conflicts in a failed cherry-pick or revertgit cherry-pick --quit
leave successfully applied commits and stop on failed cherry-pickgit cherry-pick --abort
cancel the operation and return to the pre-sequence state
git cherry-pick -n(or --no-commit) master..feature
applies all commits, and only ads to working directory and index without committing
Show log and textual diff of commit
git show <hash>
Show the diff of two commits ago
git show HEAD~2
or short version of HEAD is @
git show @~2
Show the whole file in that specific commit state
git show HEAD~3:<path>
Show the file that currently added to the index
git show :<path>
Show log and diff using the keyword that matched commit message
git show :/<keyword>
git log feature ^master
or equivalent git log master..feature
show all commits that are in feature
and not in master
Find commit message what matched pattern git log --grep <word>
. Find two alternatives git log --grep <word1> --grep <word2>
. Find both of them git log --grep <word1> --grep <word2> --all-match
Note: The pattern is case sensitive.
Trace the evolution of the line range given by <start>,<end>
(or the function name regex <funcname>
) within the <file>
git log -L 10,20:src/controllers/Auth.js
Show what revision and author last modified each line of a file git blame <path>
. To show only specific range git blame <path> -L 20,30
git log --first-parent
view history of branch in isolation
More about first-parent
https://help.github.com/articles/syncing-a-fork/
To clone shallow copy of repo
git clone --depth=1 <repo>
git clone [email protected]:whatever folder-name
clone into specific folder
Difference between git clone --mirror
and git clone --bare
described here
To show the log of references run git reflog
. It's the same as git reflog show
.
If something was added to repo by mistake and you want delete all information you need to do the following steps.
- Delete branch or commit.
git gc
runs a garbage collector that remove all unreachable refs.
Note: Deleting a branch or commit doesn't remove information from database if exists record about this commit in database(in other words, exists reference from reflog to this commit). Two options are responsible for this gc.reflogExpire="90 days ago"
and gc.reflogExpireUnreachable="30 days ago"
. It's default time for reachable and unreachable(deleted) commits. In addition, if reflog info is clear, were exist another option gc.pruneExpire="2 weeks ago"
, that allow us to checkout desired commit. In summary just running git gc
doesn't give what we want. If we force this behaviour do the 3rd and 4th step.
git reflog expire --expire=now --all
just delete all info from now from reflogs, but commit stay alivegit gc --pruneExpire=now
and done
If you want to mark some important release use tags. git tag <name>
set reference to that commit and don't change in compare of other type of refs, such as branches, HEAD. There is two type of tags: lightweighted and annotated. The previous one is lightweight. To create annotated git tag -a v1.0.0
or like in commit command -m
flag allow skip writing message in text editor git tag -a -m 'Fix performance on mobile' v1.0.0
. The difference between them is the second one add additional info about tagger and tag message when we run git show v1.0.0
command.
Show tag by commit git describe <hash>
. To archive all files from project and save on disk(flag -o
) git archive -o ~/Desktop/v0.173.0-3-gaa32694e.zip <hash or tag>
.
git tag -d <tagname>
delete tag
By default, git push
will not push tags. Tags have to be explicitly passed to git push origin <tagname>
. To push multiple tags simultaneously pass the --tags
option to git push command git push origin --tags
. When another user clones or pulls a repo they will receive the new tags.
Diff between two commits git diff <hash1> <hash2>
. This equivalent to git diff <hash1>..<hash2>
Diff between two branches git diff <branch1>..<branch2>
Difference between two dots operator and three described here
git diff
diff between working directory and index
git diff HEAD
show diff between working directory and repository(HEAD)
git diff --staged
diff between index and repository(HEAD)
git diff
and git diff HEAD
do the same if we have changes in working directory only. If the file was added to index, then show diff between working directory and index
Show difference between branches in specific file
git diff <branch1> <branch2> <file>
Show names of changed files between branches
git diff --name-only <branch1> <branch2>
Show diff outside git repository, i.e. uncontrolled by Git use
git diff --no-index <path1> <path2>
By default, diff driver not good for showing diff in text words. For that, exists flag --word-diff
. Not everything highlights diff in words by default. To add driver or rules for driver, we should create .gitattribute
file in project root.
git diff <hash> -- ':!package-lock.json'
ignore noise files from git diff output
By default, running git stash
will stash:
- changes that have been added to your index (staged changes)
- changes made to files that are currently tracked by Git (unstaged changes)
But it will not stash:
- new files in your working copy that have not yet been staged
- files that have been ignored
Adding the -u
option (or --include-untracked
) tells git stash to also stash your untracked files:
git stash -u
.
You can include changes to ignored files as well by passing the -a
option (or --all
) when running git stash.
git stash -a
.
To provide a bit more context, it's good practice to annotate your stashes with a description, using:
git stash save "add style to our site"
You can choose which stash to re-apply by passing its identifier as the last argument, for example:
git stash pop stash@{2}
You can view a summary of a stash with git stash show: git stash show
or pass the -p
option (or --patch
) to view the full diff of a stash git stash show -p
You can also choose to stash just a single file, a collection of files, or individual changes from within files. If you pass the -p
option (or --patch
) to git stash
, it will iterate through each changed "hunk" in your working copy and ask whether you wish to stash it.
To delete stash: git stash drop stash@{1}
To delete all: git stash clear
If you want to ignore a file that you've committed in the past, you'll need to delete the file from your repository and then add a .gitignore rule for it. Using the --cached
option with git rm means that the file will be deleted from your repository, but will remain in your working directory as an ignored file.
git rm --cached <file>
You can omit the --cached
option if you want to delete the file from both the repository and your local file system.
It is possible to force an ignored file to be committed to the repository using the -f
(or --force
) option with git add: git add -f <file>
If you already have unstaged changes you must run the following after editing your ignore-patterns:
git update-index --assume-unchanged <file>
If you have complicated .gitignore patterns, or patterns spread over multiple .gitignore files, it can be difficult to track down why a particular file is being ignored. You can use the git check-ignore command with the -v
(or --verbose
) option to determine which pattern is causing a particular file to be ignored
git check-ignore -v <file>
git checkout <remote_branch_name>
fetch remote branch and switch to it
git diff origin/<remote_branch_name>
show diff between origin/<remote_branch_name>
and local
git branch --unset-upstream
stop tracking remote branch
git ls-files
show information about files in the index and the working tree
git cat-file -p <object>
pretty-print the contents of based on its type
Pro Git
Atlassian Git
Git Magic
Ilya Kantor Youtube tuts
Simple git branching model
Introduction to GitLab Flow
GitHub Flow