You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stashing allows you to store files in a temporary area so you can restore them in a later time without committing them
You may run into conflicts with git stash. You will have to rollback with reset HEAD^ and commit
git stash # same as git stash save, note this saves both STAGING and UNSTAGED area
git stash save # saves ONLY TRACKED changes to a temp place and restores last commit
git stash save --keep-index # only UNSTAGED files are stashed, STAGED files are NOT stashed
git stash save --include-untracked # stash UNTRACKED files
git stash list # shows stack of stashes
git stash apply # rerun changes from top stash of stack i.e. stash@{0}
git stash apply stash@{n} # apply stash@{n} from stack
git stash drop # drop stash@{0} from stack
git stash drop stash@{n} # drop stash@{n} from stack
git stash pop # runs git stash apply then git stash drop
git stash show # show details of stash@{0}
git stash show stash@{n} # show details of stash@{n}
git stash branch <branch> stash@{0} # create branch <branch> and pop stash@{0} from stack to <branch>
git stash clear # clear all stashes
Purging History
You should AVOID doing this at ALL cost, especially if changes are pushed to remote.
You could purge history if you commited huge files or copyright issues.
git filter-branch --tree-filter "<command>"# <command> is any shell command
git filter-branch --tree-filter "<command>" -- HEAD # run <command> recursively in all commits in HEAD
git filter-branch --tree-filter "<command>" -- --all # run <command> recursively in all commits in all branches
git filter-branch --index-filter "<command"# run <command> only in staging area
git filter-branch -f --prune-empty -- --all # delete all commits that are empty
Cherry Picking
git cherry-pick <commit># pick a specific <commit> branch
git cherry-pick --no-commit <commit1><commit2># picks two commit branches, not committed yet, commit with git commit
git cherry-pick --signoff <commit># tracks signoff person who is cherry picking <commit>
Submodules
Submodules are like git repos in git repos!
Submodules allow you to share libraries across project, share changes easily
Example: Gregg and Jane wants to share /css and /js files but work on different /html.
We make changes to a submodule like git repos, but we need to update the main repo containing the submodule by running
git add <submodule>
git commit -am 'updated submodule'
git push
git submodule add <repo># add <repo> as a submodule
git submodule init # initialize submodules in .gitmodules file
git submodule update # pulls and clones submodules from the internet after git submodule init
Reflog
Git never deletes anything
Even after deleting a commit with reset --hard HEAD, we can still access it via git reflog.
Reflog is only for local repositories, a git clone will start a new reflog.
Git is a distributed version control system (DVCS) as opposed to a central repository system.
A central repository system can be pictured as: ((userA, userB, userC), server)
A distributed Repository system can be pictured as ((userA, server), (userB, server), (userC, server))
Setup
Configure global settings and add some pretty command line colors :)
git config --global user.name "<username>"# set <username>
git config --global user.email "<email>"# set <email>
git config --global color.ui true# turn on colors
git config --list # see configurations
Basic Commands
git init # Initialize LOCAL (not a remote) repository
git status # check changes since last commit
git add <file># add <file> to stage
git add --all # add all new and modified files to stage
git add docs/*.txt # add all txt files in docs directory
git rm <file># remove <file> and add changes to stage
git rm --cached <file># stop TRACKING <file> but does NOT delete <file>
git commit -m "<message>"# commit changes from staging area with a <message>
git commit -am "<message>"# add and commit all TRACKED files with a <message>
git log # show history log
Staging and Commits
git diff # show UNSTAGED differences since last commit
git diff --staged # show STAGED differences since last commit
git reset HEAD <file># unstage <file> from stage
git reset --soft HEAD^ # undo last commit and put changes into staging
git reset --hard HEAD^ # undo last commit and all changes
git reset --hard HEAD^^ # undo last two commit and all changes
git checkout -- <file># blow all changes for <file> since last commit
git commit --amend -m "<message>"# add to previous commit with <message># Note that HEAD refers to last commit on git history# Try to only use reset and ammends before pushing to remotes, since it affects commit histories.
Remotes
git remote -v # show remote repos
git remote add <remote><address># add new <remote> to url address e.g. <remote> = origin
git remote rm <remote># remove <remote>
git push -u <remote><branch># push local <branch> to <remote> e.g. <remote> = origin, <branch> = master
git pull -u <remote><branch># pull changes from <remote> to <local># Note that the -u syntax helps cache the <remote> and <branch> of repos to avoid future typing
Local Branches
git clone <remote><name># clone git repo from remote url into folder /<name>
git branch # check name of current branch
git branch <branch># create branch <branch>
git checkout <branch># go to <branch>
git checkout -b <branch># create branch <branch> and go to <branch>
git merge <branch># merge <branch> into current branch
git branch -d <branch># delete branch <branch># Note git merge can be fast-forward or recursive. A fast forward merge is efficient when there# are only changes in one branch. A recursive merge is more intensive and is involved when# there are changes in both branches that are to be merged.
Collaboration
Assume two collaborators, Gregg and Jane are working off the same remote.
No merge conflicts
Jane git push her changes and Gregg tries to git push later.
Gregg will encounter an error since his commit is behind the timeline now.
Gregg needs to git pull first before git push. This essentially executes:
git fetch which syncs his local repo with the remote repo
This does not change any local code, only updating the repo.
In Gregg's local repo, there is actually a branch origin/master
git merge origin/master which merges the branch origin/master to Gregg's current branch i.e. master
Now when Gregg uses git push, origin/master is in the same state as his local repo
Merge conflicts
Gregg and Jane are both working on the same file README.md
Jane has committed her changes and git push to remote while Gregg has only commited locally.
Gregg executes git pull but encounters a merge conflict in README.txt
Gregg goes into README.txt with vim and needs to manually fix the issues e.g.
<<<<<<<< HEAD
the cake isa lie. # this is Gregg's local version========
the cake is telling the truth! # this is Jane'sversion
>>>>>>>>
Gregg manually fixes the file and runs git commit -a
Now Gregg has fixed the merge conflict and simply needs to run git push to be in sync with the timeline.
Remote Branches
git checkout -b <branch># create local branch <branch>
git checkout -b <branch><remote>/<branch># create local branch from <remote> <branch>
git checkout --track <remote>/<branch># shorthand for the above
git push -u <remote><branch># push <branch> to remote repo branch and start tracking it
git branch -r # list all remote branches
git checkout <branch># automatically pull remote <branch> into local <branch>
git remote show <remote># show remote and local branches e.g. <remote> = origin
git push <remote> :<branch># deletes ONLY the remote <branch> NOT the local <branch> e.g. <remote> = origin
git branch -D <branch># force deletes local <branch> manually after deleting remote branch
git remote prune <remote># clean up old and stale branches and references that are deleted on <remote>
Tags
git tag # list all tags
git checkout <tag># checkout code at commit
git tag -a <tag> -m "<tagname>"# add a new <tag> called <tagname>
git push --tags # push new tags# A tag is a reference to a commit. Used mostly for release versioning
Rebase
Run git fetch first
Switch to branch with git checkout <branch>
Then run git rebase:
git rebase does a few things different from git fetch and git merge origin/master
Move all changes from local master which are not in origin/master to a temporary area, say temp
Run all origin/master commits one at a time.
Run all commits in temp (i.e. commit diffs) one at a time.
Note that there are no merge commits, they are run one at a time!
We can potentially run into merge conflicts.
At this point git status will show us that we are in the process of a rebase
Manually fix conflicts and add files with git add <file>
Continue rebase with git rebase --continue
Finally run jump back to master branch with git checkout master
And merge branch to master git merge <branch>
History and Configuration
History
git log --pretty=oneline # displays a pretty one-line
git log --pretty=format: <format># displays pretty format
git log --oneline # see git timeline in single line
git log --oneline --graph # see git timeline in graph format
git diff HEAD # same as git diff
git diff HEAD^^ # compare current commit against 2nd most recent
git diff HEAD~5 # compare against 5 commits ago
git diff <branch1><branch2># compare diffs between two branches
Alias
git config --global alias.<aliasName>"<command>"# set alias <aliasName> given a <command># Examples
git config --global alias.st "status"
git config --global alias.co "checkout"
git config --global alias.br "br"
git config --global alias.ci "commit"
Other
Use .gitignore to ignore files and folders e.g. logs/*.log
Put these in a Github wiki or a dot files folder e.g. .gitconfig
git config --global --push.default simple # push current branch (not matching branch) this is default in git 2.0+
git config --global --pull.rebase true# git pull will git fetch then git rebase instead of git merge
git config --global --rerere.enabled true# resolve similar merge conflicts
git config --global --colors.ui true# for older versions of git
git config --global alias.s "status -s"# silent mode git status
git config --global alias.lg "log --oneline --decorate --all --graph"# super git log decorations
Forking and Cloning
Anyone can git clone a repo.
You can only git push changes to Github if you are a collaborator.
If you are not a collaborator, you need to fork the original repo instead
With the forked repo, you can now git clone and git push to your forked repo
Pull Request
When you fork a repo and make changes to your local repo and forked repo, you can contribute back to the original source by making a pull request.
A pull request is to request for changes on our master branch to be merged back to the original master branch
On Github, you can create pull requests with buttons add comments as needed.
Pull Request Review Workflow:
git fetch # download latest changes and all branches from Github
git branch -a # view all branches (including remote tracking branches in red
git checkout <branch># check out a local branch pointing to remote tracking <branch>
git commit # after making changes, commit them
git push # push changes
Updating Forks
To collaborate across forks, we need to pull from various upstreams to get updated commits
We should do the following everytime a pull request is accepted into the upstream repo:
git remote add upstream <repo># add upstream (original) repo based on <repo> url path
git fetch upstream # update upstream data and fetch changes
git merge upstream/master master # merge upstream master branch to local master branch
git push origin master # push your final changes up to your remote
Single Repository Workflow
It can become hard to manage Fork-based repository workflow as everyone is working on their forks and have to check for pull requests and upstream to keep updated.
A single repository workflow helps solve this where everyone just clones from the single repository.
The problem with single repository workflow is that if there are many contributors, then they may run into conflicts.
This problem is solved with feature branches.
Feature Branches
Everyone is contributing separately on their own branches.
Multiple developers can collaborate on each other's branches easily by checking them out
git fetch # fetch from remote server
git branch -a # show all branches
git checkout f2 # checkout feature branch f2
Developers will merge each others' feature branches.
Eventually, they will make a pull request to merge their feature branch back to the remote.
Merging Pull Requests
Three key considerations:
Interactive rebase
Great for simplifying history by pick or squash commits.
Be careful not to squash an entire branches, some information is better than none.
Squash commits that are no longer neccessary.
Rebase
Simplifies and linearizes history.
This is as simple as
git checkout feature_branch
git rebase master
Fast-forward or recursive merge
Fast forward has less commits as commits on feature branches are placed directly in master branch
The downsides of fast-forward is that it is harder to tell what commits are made on various feature branches
A recursive merge is recommended.
We can do so by explicitly using the --no-ff option in git merge