- What is Git?
- What is Source Control?
- Why use Source Control?
- What is the difference between Git and GitHub
- Getting started
- Overview
- Git Config
- Collaboration
- git merge
- git rebase
- resolving conflicts
- git reflog
- git reset
- Fork & Push Workflow
- git fetch
- git pull
- git push
- git remote
- Setting up gitHub SSH key
- Tools
- git stash
- git tag
- git grep
- git blame
- git bisect
- Automation
- Git Hooks
- Free Books
- Useful Links
Git is a Source Control (aka version control) tool: it allows you keep a history of changes to a set of files, and makes it easy to retrieve a different revision of the file at any point in time. This revision history gives you the freedom to experiment without fear of losing work you have done previously. At any point in time, you can review your changes and revert to a previous version if needed.
Git is a Source Control tool. There are other Source Control tools, such as SVN and Mercurial.
GitHub is a web service that hosts your Git repository, making it easier to collaborate with other people. There are other similar web services, such as GitLab and BitBucket.
The general idea is to create a branch of a base branch (aka: trunk) and work on your branch until it is ready to be merged onto the trunk. Each commit is a set of related changes saved to the local branch, and you pull the latest changes from the trunk to keep up to date.
git help
takes a parameter and opens the local git documentation for the
given parameter.
ie: git help help
git init
sets the current working directory to be tracked by Git's source
control.
git clone
clones an existing repository to your local machine. It can be used
to clone another local repository, as well as a remote repository.
git branch
allows you to view your existing local and remote branches, as
well as create a new branch.
git checkout
switches your repository to track the given branch.
git status
displays all of your local, uncommited changes, as well as merge
conflicts. Uncommited changes can be classified as staged and not staged.
Staged changes are ready to be commited.
git diff
displays your unstaged changes. Once changes are staged, you can see
them with git diff --cached
git log
displays the history of commits on the current branch
git add
stages a file so that it can be commited.
git rm
removes a file and stages the deletion so that it can be commited.
git mv
moves a file and stages the move so that it can be commited. This is
useful for renaming files as well.
git commit
saves your staged changes to your history with a given comment.
git revert
creates a new commit reverting the changes specified by their
hash, listed in the history log.
Git allows you to create a configuration file, where you can store your preferences such as editor and difftool, create aliases for commonly used commands, set up your identity to be used on git commits, etc.
Here is a sample .gitconfig:
[user]
name = Allan Goncalves
email = [email protected]
[color]
ui = true
[log]
# Better date formats in logs
date = rfc
[core]
# Set default editor for git commits
editor = vim
# let the system figure out the correct line-ending to use
autocrlf = input
# Use custom `.gitignore`
excludesfile = ~/.gitignore
[push]
default = simple
[alias]
st = status
It is a good practice to create your own .gitconfig in your home directory
(~/
on unix)
In order to collaborate with other people, each person will branch off of a base branch, and create a Pull Request to merge changes when ready. It is common for a conflict to arise when merging changes if the base branch has changed since you branched off. A good practice is to fetch the latest changes to the base branch and merge them into your branch often, and always do it before creating a PR.
git fetch
will fetch the changes, and git merge
will merge them. This is
such a common use case that there exists a command git pull
that does both
fetch and merge.
An alternative to merging is rebasing, which allows you to modify the history
of your branch so that your commits appear after the commits from the base
branch. This can be done with git rebase
. It is a good idea to use the -i
flag for interactive rebase. Be careful modifying history, as it can and will
cause conflicts. It is best practice to only rebase while working on a local
branch, and always merge if your branch is accessible to other contributors.
This is also important if you create a PR and need to make changes after the
code review. If you modify the history, it is much harder for the code
reviewers to track what has changed since the last code review.
When merging or rebasing, you may face merging conflicts. The basic way to
solve a conflict is to edit the file contents between the following markers
>>>>>>>>>>>>>>
==============
<<<<<<<<<<<<<<
Once the conflict is resolved, you can either commit the changes, or in the
case of a rebase, stage the changes and run git rebase --continue
. If you
want to give up on the rebase and go back to what you had before, you can use
git rebase --abort
.
Should you ever find yourself wishing you had not rebased after the rebase is
completed successfully, you can use the git reflog show
command to view your
git command history and use git reset <hash>
where <hash>
is the hash for
the change you want to go back to.
The git reset
command does a soft reset by default, so you still have a
chance to review the changes before they are final. If you know you want to
reset and do not need to review the changes, you can use the --hard
flag
(git reset --hard <hash>
).
A common git collaboration workflow is known as "Fork & Push". It requires each collaborator to fork the original repo and push changes to their forks, which then allows them to create a Pull Request against the origin repository. This workflow prevents unintentional updates to the origin repository, as every update must first go through a Pull Request and Code Review. GitHub allows you to protect the origin repository from direct changes as well.
When using this workflow, you will need to set up multiple repositories
(origin
+ you fork aka upstream
). You always fetch
/pull
from upstream before
creating a branch, and before rebasing or merging. Additionally, you never push
to upstream. Always push
to origin instead.
It is a good idea to setup an SSH key to interact with GitHub, you can follow the instructions to set that up:
Git offers much more than that... Here are some useful tools:
git stash
allows you to quickly store your changes in case you need to switch
to another branch in the middle of your work. The -u
flag will also stash
unstaged changes. git stash list
will list all of your stashed changes, and
git stash pop
will attempt to apply the top of the queue to the current
branch.
git tag
allows to vesion the current commit in a tag, for easy access later on.
git grep
allows you to search all files in your branch for a given string or
regexp. You can limit the search to a specific file type.
ie: git grep "search" -- **/*.txt
will search for "search"
in txt files
git blame
gives you the history of a file, line by line, including who made
the change and when it happened.
git bisect
is a binary search through your commits. You define a good state and a
bad state and git will run a binary search to pinpoint where the issue was
introduced.
Git hooks allow you to automatically run scripts before or after certain actions. eg: This can be useful for linting your files or formatting them before commiting.