Git Notes
Table of Contents
Definitions
- Commit
of a project content in al particular time. It contains a tree at that revision and a reference to his parent(s) commit.
- Branches
Parallel lines of development.
- Branch head
A head that reference the last commit of a branch.
- HEAD
Special symbol typically used to refer to the current branch head (in a non-detached1 mode); you can see the content of head in
.git/HEADfile.- Reachable commits
Reachable commits from commit X are all ancestors from X (parents, grandparent, and so on …).
- Tag
Like heads are references into project’s history, but the main difference is that tags are expected to always point at the same version of a project, while heads are expected to advance while development is in progress.
- Index
Just a file (
.git/index) that stores the tree needed to create a new snapshot. In a higher level you can think about the index as a staging area.- Blob
Just stores file content.
- Tree
Consist of blobs and other subtrees to conform a directory structure.
- Tag object
Symbolically identifies and can be used to sign other objects.
- Git object
Either a blob, tree, commit or tag. Every commit has a 40-hex digit id called “object name” or “SHA1 id”.
- Object database
All the data related to git objects in a repo, they can be found in
.git/objects.
Commands
git reset
Moves the head of a branch (destructive command, use carefully)
Examples
To go back to previous commit before merge (delete merge commit).
git reset --hard ORIG_HEAD
git show
Shows the most recent commit on the current branch (in non detached mode), in detached mode apparently shows the commit whose HEAD is pointing to
git clone
Clone the content of a repo into a directory. Clone can be downloading from internet (the
typical use case) or syncing from a local path – when using a bare repository in
localhost for instance.
Git creates the following branches when using git clone command.
- A master branch from
HEADin the remote repo. - A remote branch for each of the branch in the remote repo that can be updated using
git fetchorgit pull(this branches can be retrieved usinggit branch -rcommand)
git merge
This command is typically used in a context where there are divergent branches that you want
to merge in a new commit. Or when you want to “update” a local branch head with his remote
counterpart, for example using git pull.
Examples
Suppose the following tree of revisions.
* c575639 (HEAD -> master) added file4.txt
* 0a55977 updated f1 and added f2
| * d475e54 (dev) added f5
| * 3304a47 added file3.txt
|/
* 0b0496a added file1.txt
Then, you can do git merge dev to merge the dev branch into master branch. After
executing the previous command you should expect the following output to save a new message
for the merge commit in you preferred editor.
Merge branch 'dev'
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
After the merge the new tree should look like the following.
* 1efbbb9 (HEAD -> master) Merge branch 'dev'
|\
| * d475e54 (dev) added f5
| * 3304a47 added file3.txt
* | c575639 added file4.txt
* | 0a55977 updated f1 and added f2
|/
* 0b0496a added file1.txt
(Note that the current branch head is moved to the new merge commit.)
Sometimes, divergent branches change the same file generating a ‘merge conflict’.
Notes
git mergedoes not yield conflicts when changes are in adjacent lines.- Sometimes you use
git mergetoolto resolve a conflict in a file, but after adding it to the staging area you realize that you made a mistake and the file don’t resolve the merge properly so you would like to revert the changes and usegit mergetoolagain to fix the issue, in that casegit checkout -m path/to/fileallow you restore the file to the conflict state.
git merge-base
Find common ancestor.
git log
List commits from a parent.
Examples
Commits not including v2.5 ancestors.
git log v2.5..
Commits that are ancestors of test but not master.
git log test.master
Commits from last 2 weeks.
git log --since="2 weeks ago"
Commits that touch file Makefile
git log Makefile
To show commits that touch unmerged files between merging branches
git log --merge
All commits from master branch.
git log master
All reachable commits by master branch but not dev branch.
git log master ^dev
All commits in master but not in dev that touch path/to/file
git log master ^dev -- path/to/file
Commits that match a regex string in its commit message (it match against the whole message not just the title).
git log --grep="test"
Look for git history (patch text) that contains a given regex pattern;
git log -S <regex>
git diff
Show the difference between files in different snapshots.
Example
Diff between working tree and index.
git diff <path>
Diff between the index and commit (HEAD, when omitted).
git diff --cached <path>
Diff between working tree and commit.
git diff <commit>
git diff <commit> <commit> -- path
Notes
- If you change just a word inside line that consist of more characters, then the output of
git diffisn’t going to point the change word wise, but you can alternatively use adifftoollikevimdiffwhich is going to mark the change as word wise. - Diffs can be managed using 4 different algorithms:
- Myers (default)
- Minimal
- Patience
- Histogram
Examples
Diff between two commits
git diff master..test
git diff master test
Changes between test and the merge base commit of test and master this is a shortcut for
git diff ${merge-base master test} test.
git diff master...test
git rm
Always use git rm instead of rm on tracked git files.
git show
Show info related to git object, typically is used to view the content of file in previous versions.
Examples
Show the content of the blob/file locks.c in a commit referenced by version v.25.
git show v.25:fs/locks.c
Typically if u use git show with a commit it outputs the diff of the files modified,
added, etc. But sometimes you just want to know what are the files touched by a particular
commit without getting the huge diff output. In this case you can use the beneath command.
git show --compact-summary <commit>
git revert
Revert the changes made in commit HEAD~1; revert basically fix a mistaken commit with a new commit.
git revert HEAD~1
git restore
To use HEAD~6 version of path/to/file2.
git restore --source=HEAD~6 path/to/file
git rebase
It applies a set of patches3 on top of another branch to maintain a linear history.
git rebase is used to maintain the history of commits simpler without any merge commit.
Before rebase.
o--o--O--o--o--o <-- origin
\
a--b--c <-- mywork
After rebase.
git switch mywork
git rebase origin
o--o--O--o--o--o <-- origin
\
a'--b'--c' <-- mywork
Notes
Note that you can use git mergetool to manage rebase conflicts, then you finish the rebase
with git rebase –continue and saving the new commit.
If you want to do a rebase but with some changes like:
- only pick specific commits
- edit commit messages
- melt commits into a single one
- make changes in a specific commit
Use git rebase -i.
git cherry-pick
Select arbitrary commits to create a new commit.
Revisions
A revision can be:
- Specific commit.
- Set of commits.
- Blob.
- Tree.
- …
Single revision
@ notation
@ is a shortcut for HEAD, for example.
git switch --detach @~3
{n} notation
master@{3} is the third previous commit where master branch head pointed to.
^n notation
HEAD^2 is the parent number 2 of HEAD.
Also HEAD^1 is equal to HEAD^.
~n notation
HEAD~2 ancestor number 2 (always first parent).
HEAD~1 is equal to HEAD~.
HEAD~4 is equal to HEAD^1^1^1^1.
: suffix notation
master~2:README shows the blob README.
Range revision
Use a single revision in this context means all the commits reachable from the commit referenced by the single revision.
^ not notation
Objects reachable from master, but exclude the ones reachable from branch.
master ^branch1
.. notation
dev..master is a shortcut for ^dev master
... notation
dev...master all commits in master and dev but not in git merge-base --all dev master.
Misc
Tags, branch heads, remote-tracking heads and everything that reference a commit is named under the name
ref/...4, for example master is a shorthand forref/heads/masterand a tag likev2.5is a shorthand forref/tags/v2.5or a remote branch likeorigin/developmentis a shorthand forref/remotes/origin/development.There are different ways to name commits apart from branch name, tag name, HEAD, for example:
- ORIG_HEAD; used in git reset.
- FETCH_HEAD; used in git fetch.
- MERGE_HEAD; used in git merge.
Git maintain5 a log6 for each branch, recording each movement of the branch head, so if you accidentally made a mistake using
git resetyou can still recover lost commits.Examples:
To log previous commit where master pointed to.
git log master@{1}To move master head to where it previously pointed to.
git reset --hard master@{1}To log 1 week old commit commit where master pointed to.
git log HEAD@{"1 week ago"}
HEAD is detached when points a commit that isn’t a branch head. ↩︎
The difference between using this command and doing a
git checkout HEAD~6 -- path/to/fileis that checkout automatically addpath/to/fileto staging area. ↩︎This patches are present in one branch but not in the other, for example if some patch is present in both branches
git rebasedon’t duplicate the patch. ↩︎In fact this name and path’s relatives to
refcan be found in.git/ref. ↩︎By default Git stores reflogs for 30 days. ↩︎
Apparently this logs are stored under
.git/logs/refs. ↩︎