A Guide to Mastering Git
What is Git?
Git is a distributed version control system. A version control system records changes to files over time so that you reference specific states of the file later. Distributed means every copy of the codebase has the same functionality (no central authority necessary). GitHub is a central authority designed to simplify using Git, but you can still use Git without it! To review the basics of Git before getting started, checkout this tutorial.
Commits and Branches
A commit is a snapshot of the repo at some point in time. Each commit is identified by a hash and represents any changes made to the files that came before it. A branch is an independent line of development with a movable label attached to a single commit. To sign off of a commit, type:
$ git commit -sm <"SOME COMMIT MESSAGE">
//a normal commit message would be$ git commit -m <"SOME COMMIT MESSAGE">
The HEAD
Every clone of the repo has a unique HEAD which points to the current commit. HEAD^ points to the parent of the current commit and HEAD^^ points to the parent of HEAD^. To go back to the previous commit, run one of the following commands in terminal, where <COMMIT_HASH> is the hash of target commit.
$ git reset --hard HEAD^$ git reset --hard <COMMIT_HASH>
The previous commands allow you to look at a previous commit without changing where HEAD points to. This means you’ll have something called a “detached HEAD”, you won’t be on a branch and your previous branch will still point to the same commit. If you commit here the commit will not be attached to any branch. To create a branch pointing to this commit, type:
$ git branch <SOME_BRANCH_NAME> <COMMIT_HASH>To access commit hashes, type
$ git reflogto print a list of all the commits HEAD has pointed to. After viewing the old commits, type
$ git checkout YOUR_BRANCHto navigate back to your branch.
Adding Changes
To add all your changes:
$ git add --allTo add just the changes from your current directory:
$ git add .Creating a New Branch
To create a new branch and move HEAD to it:
$ git checkout -b SOME_BRANCHTo create new branch without moving HEAD:
$ git branch NEW_BRANCHMerging
Merging adds changes from a target branch to the current branch. To add your personal commits to master:
$ git checkout master
$ git merge <YOUR_BRANCH>There are two types of merging: merge commits and fast-forward merging. Merge commits create a new commit that represents the merged state. This commit will have two parents at this time, the two merged branches.
Fast-forward merging occurs when when a target branch is the child of the current branch or vice-versa. In this case, git will move HEAD to the later commit without creating a new commit.
Rewriting History
You can ‘rewrite’ history using rebase commands. Rebase changes the base of a commit by taking a divergent situation and linearizing history. Below is an example of rebasing.
//add on the changes to the end of master's branch (merge conflicts will have to be settled during the rebase not the merge)$ git rebase master
//git merge master is now a fast-forward merge$ git merge master
Many open source projects prefer fast-forward merging, so rebasing is how you would avoid merge commits.
Git Pull
Running git pull is the same thing as running $ git fetch followed by $ git merge.
$ git pull = $ git fetch + $ git mergeGit fetch copies all the commits from the remote repository and git merge merges the commits. If the local repo and the remote repo have diverged the git pull command will result in a merge commit.
Git Push
Git push merges changes from a local repository to a remote repository. Note that git push won’t work if your local branch isn’t up to date because it only permits fast-forward commits. Remote repositories are often shared, so be deliberate about non-safe merge operations. To avoid merge commits, type:
$ git pull --rebaseIf you want to keep your changes locally but are not ready to push them, commit and don’t push! Your changes will still be saved.
Takeaways
- Git history is a series of commits
- Branches are pointers to commits (like sticky notes you can move around with
$ git branch) - You can switch branches with
$ git checkout - Merging branches usually creates a new commit with two parents
- Fast-forward merges are when the target branch is a child (i.e. ancestor) of the current branch
- Rebase: rewrite history so it is flat (i.e. no merge commits with multiple parents)
- Pull: merge from remote to local
- Push: merge from local to remote (Non-fast-forward merges disallowed for safety)
