Next Level Git
It is important to understand that every git repository is completely standalone and functional by itself, without dependency on other repositories. Main commands we covered in the git fundamentals section (pull, push, fetch) enables transferring/sharing different versions of the code to other repos.
In this section, we will dive deeper into git structure and other git commands and tools to help improve productivity.
Resources & References
There are great resources on git.
Git Structure
Intro to git internals
Git repo is basically a hidden directory (.git) at the top level of your repo. It holds everything that is needed to track the needed changes. If you want to backup your repo, this is the only directory you will need.
For more background on the Git internals, check out Git book.
HEAD is a symbolic reference to the branch you are on. Git is a tree structure where each commit creates a new node in that tree, and git commands help navigate that tree.
Git is immutable by design -- every new change creates a new set of nodes, which makes git almost indestructible.
Branches and Tags
A branch is a pointer to a specific commit. Switching branches walks the tree to derive the history of the repo. git tag is similar to git branch, however it operates like a bookmark to a specific point in time.
In git, branches basically another node in the tree -- this makes them lightweight. Many teams use feature-driven branching to aid their workflow.
git tag is useful for marking special releases. A tag can be lightweight, just a pointer, or annotated w/ tagger name, description, date, etc.
Important by default, git push does not push the tags or the branches to the remotes. You need to explicitly share them.
Git HEAD
By now you may be wondering what "HEAD" is and why it's possible to become detached. HEAD is git's way of referring to your current view of the repository, and corresponds to a single commit hash. Generally, this means HEAD matches the lastest commit on your current branch. A detached HEAD state means that you no longer are viewing the latest commit on a branch, and are instead veiwing an intermediate commit. As such, making additional commits will not directly contribute to the history of one of your branches, and will require more finesse to integrate into your project.
This does not mean that the detached HEAD state is useless. Far from it. It is a great way to rewind history and examine previously working bits of code, in order to find out where it all went wrong.
Git checkout performs double duty. When used on a branch, tag, or commit hash it will move your HEAD to the corresponding commit, changing the view of your repository. If used on a file, it will modify the file to the version it was in in the appropriate commit (which defaults to HEAD). The changes will happen in your current branch/state, meaning it will then be possible to commit the old version of the file to your current branch.
For convenience, HEAD^ refers to the commit before HEAD, and HEAD^^ to the commit before that.
Tracking and merging branches
By default, git branches do not know about each other. Tracking creates linkages between the two repos, making it easier to stay in sync between two repos as git will inform you if your branch is ahead or behind the tracked branch.
Branches explicitly need to be pushed to remotes. Similarly, explicitly deleted. Note, you can also use GitHub interface for deleting branches on remotes.
While git branch creates a fork in the road, git merge allows the forked history to be integrated again. A typical example is to merge a feature branch to master. Process overview:
checkout the branch to be updated
specify the merge from a target branch
optional: delete the target branch
If a conflict occurs during merge that git needs you to decide, git will edit the content of the affected files with visual indicators: <<<<<<<, =======, and >>>>>>>. You can search for these indicators to resolve the conflicts.
git rebase & git squash
git rebase is basically merging w/ history -- git takes commits in one branch and attempts to "replay" the differences onto the other branch.
git squash condenses the commits, think G-rated version of sausage making, creating a concise and readable history. Interactive rebasing allows selecting and squashing commits.
Reverting changes
There are different ways to undo prior changes and commits.
revert takes a specified commit and creates a new commit which inverses the
specified commit -- safe operation as creates a new commit
reset takes a specified commit and resets to match the state of the repo at that specified commit -- can cause conflicts is history is changed
Some common operations are below.
Git Commands & Helful Tools
Git bash completion
If you are using bash shell, there is a nice auto-complete feature you can enable for git.
Follow the instructions for setting it up: git-completion.bash.
More on gitconfig
gitconfig has handy tools/options from customizing git colors to setting aliases. More on gitconfig.
git diff
Git can show you a list of differences between two commits, or a list of differences between a given commit and the current state using the command git diff.
git stash
There are times when you are not ready to commit, but you need to change branches -- git stash is to your rescue. It stashes your changes to be returned to at a later time.
git references or refs
Instead of referencing git contents via sha-1 value, such as git log 1a410e
, you can create named references to that value.
git branch <branchname>
creates refs using git update-ref
command to add the sha value with the given branch.
remove or move a file: git rm && git mv
There will be times when you need to remove a file from your git repo, use git rm or remove command. And, when you need to move or rename a file, use git mv or move command.
Last updated