Git essentials
Learning note from “Version Control with Git” by Atlassian offered by Steve Byrnes on Coursera.
Git common usage
Types of content for git
Basically any content you want to manage and continuously improve
- source code
- automated tests
- server configuration
- documentation
- a book
- web site content
Git setup
Configure user name and email address: --global
flag to configure every repo on a given computer, --local
flag (or no flag) only applies to the current repo.
git config --global user.name "first last"
git config --global user.email "xyz@gmail.com"
From local repo to remote repo
Scenario 1. You have not started working on anything and you plan to build on top of an existing repo. Go to the remote repo site and copy the url that ends with .git
(such as https://xyz.git).
git clone https://xyz.git
to local dir. Go to step 1 below after that.
Scenario 2. You did a lot of work locally and now you want to add them to a remote git repo.
git init
to initialize a .git
dir, which contains information about git. Delete .git
dir will remove all the git histories. Create (no need to init additional files otherwise there will be conflicts) or identify a remote repo (e.g https://xyz.git, use git pull https://xyz.git
if this repo is not empty )
git remote add origin https://xyz.git
, origin is a name we call the remote repo by default.
git remote --verbose
to see the details of remote repo.
After this point, the remote repo is all setup. Let’s look at how to let git know the changes we made to local repo:
Step 1. Stage files using git add <filename_x>
, filename_x
will be tracked by git after this step. Before this step, filename_x
would be either untracked by git or tracked by git but had not been updated.
Use git status
to view file status tracked by git.
Step 2. Add staged files to local repo using git commit
.
Use git log
to see the history of commit messages, --all
tag to show all branches.
git log --oneline --graph --all
Step 3. Push current ‘commits’ to remote repo using git push
to a specific branch.
git push --set-upstream origin master
means you want to push all commits of the current repo to the master
branch of a remote repo called origin
. -u
is to link the current local repo to the origin remote repo.
Vocabulary:
The master
label represents the tip of the local master
branch.
The origin/master
label represents the tip of the tracking branch (defined as a local branch that represents the remote branch) of remote repo origin
‘s master
branch. It can become out of sync with local branches, one updates it by using git clone/fetch/pull/push
.
git pull
combines a fetch and a merge, it is recommended to do git pull
before git push
, as there might be updates made by other people to the remote repo.
git push
adds commits to remote repo.
Advanced usage
Git references
Git has one HEAD per repo. HEAD usually points to the current commit. Use git show HEAD
to show the HEAD content. Checking out a past commit will create a “Detached HEAD” state (updated HEAD reference). One can checkout a past commit and make a branch off there (see how in “Git branches” section).
Git tags
Tag is a reference attached to a single commit. One can tag a commit to sign off a release. Annotated tags are more useful because you can associate it with more info.
#tag a commit, -a means annotated, -m is for message
git tag -a -m "message associated with this tag" <tagname> [commit_ID]
#tag current commit
git tag -a -m "message associated with this tag" <tagname>
# show available tags
git tag
# show specific info (commit info) of a tag
git show <tagname>
Tags need to be independently pushed by git.
#for a single tag
git push <remote> <tagname>
# for all tags
git push <remote> --tags
Git branches
Allow independent work of many people on a project without conflict.
Make a new branch and update HEAD reference to the new branch. -b
only works when the new branches hasn’t been created.
git checkout -b new_branch_name
The above is equalvent to
git branch new_branch_name
git checkout new_branch_name
Switch to an existing branch (update HEAD reference)
git checkout exsiting_branch_name
Delete a branch (usually done after merging branch_to_delete
content to master branch). If branch_to_delete
has commits that haven’t been merged, one can still use -D
to delete the branch but this will create “Dangling commits”, eventually these commits will be garbage collected and removed.
git branch -d branch_to_delete
Undo an accidental branch delete
# The accidental deletion of branch
git branch -D branch_to_delete
# get local recent commits
git reflog
# find dangling commits from local commits and re-create the branch
git checkout -b new_branch_name <commit_ID>
Git merge
Best practice: create small and frequent merges
- Fast forward (FF) merge (creates a linear git history). This type of merge assumes nothing was done on base branch after the
branch_to_merge
was created. The fast forward merge only updates HEAD reference from old place to the updated place on a feature branch (see below).
- Merge commit (creates a new commit by merging lastest commits of merged branches, it has multiple parents. Use
--no-ff
tag).
git checkout common_base
git merge --no-ff new_feature_branch
Solving merge conflicts
Merge conflicts occur when a same file is edited in different ways on two branches, and one wants to merge these two branches.
How to:
- checkout master -
git checkout master
- merge featureX: conflict (
git merge featureX
) - both modified fileA.txt (git status
will show you this) - fix fileA.txt
- stage fileA.txt -
git add fileA
- commit and merge commit -
git commit -m "message"
- optionally remove
featureX
branch
Git rebase
Git rebase rewrites commit history.
Rebasing is a type of merge. Git changes one branch’s parent to a commit of another branch.
A <–B
\<—C
becomes A <–B <–C’
git checkout featureX
git rebase master
# is same to
git rebase master featureX
Fixing a merge conflict when rebasing:
git checkout featureX
git rebase master
: might have conflictgit status
: find conflict, resolve itgit add file_with_conflict
git rebase --continue
Rewriting history
Amend a commit
- change commit files but not the message
git commit --amend --no-edit
Squash merge
git checkout master
git mrege --squash featureX
git commit
More advanced usage (e.g edit commit message, drop/delete commits, squash, fixup, reorder commits)
- git interactive rebase
git rebase -i the_1st_parent_of_commit_to_modify
Pull request
The goal of a pull request is to merge a branch by asking specific reviewers to approve the merge before it happens. Pull request can be opened anytime after a branch is made. No need to edit the pull request if one add more commits to the branch.
Contribute others repo using fork
Forking a remote repo creates a different source of truth, one usually forks other people’s repo and works on it so that it can be merged to the the upstream repo (where it was forked from) with a pull request.
Git workflow
Contains long running branches and short-lived branches. The master and develop branches are only the long running branches. Releases only happen on master, and are tagged. Most of the work are done on develop branch, feature branches are add-ons and will be merged to develop branch and deleted afterwards. Bugfix branch (release1) is short-lived and will be merged to both develop and master branches. Hotfix branch for released features is branched off master branch, because there could be more work done on develop branch since the release. See below graph taken from the course.