Git Primer

11 minute read

Published:

This primer introduces the basic commands and workflows in the Git™ Version Control System (VCS). For a more detailed look at the workings of Git, refer to the free resource hosted as part of the Git open-source project - git scm book.

Git™ - Quick Primer

A fast-paced introduction to version control and git. If you want the full blown experience, see the git scm book.

What is version control

Version control is maintaining a detailed report of changes that happen to your codebase. Good version control practice allows you to roll back mistakes, work on features in parallel, and combine them into a final product.

How does Git record history?

  • A git repository consists of a collection of branches.
  • Each branch is a sequential series of commits.
  • An individual commit describes what changed since the last commit.
  • Each commit has a unique hash that identifies it among all other commits.
  • Changes are usually introducing or removing lines from a file, deleting a file, or renaming a file.

How do I see the history?

Use git log <branch> <files> to see a list of commits on branch that edited files (or any files, if absent).

The git workflow

  1. Working set
    • The working set is the state of the files as they are on your machine, right now.
    • When you make changes, you are editing the working set, making those files modified.
  2. Staging area
    • The staging area (also called the index) is for files that you have finished editing and want to commit the next time git commit is run.
    • A file can be both staged and modified if you change it after staging via the git add command. Simply stage it again to update the staging area.
  3. Committed files
    • Within .git directory, git holds data structures that describe what it currently believes the file should look like.
    • You diverge from this state when editing, but then tell git about the changes by committing.
    • HEAD is a special tag that indicates the commit the index currently represents. Most of the time this points to a branch, but can potentially not be pointing at a branch (see below).

Moving inside the workflow

You want toType
Make your working copy of a file look like how it used to in some past commit (pass HEAD to essentially drop modified or staged changes)git checkout <commit-hash> <files>
Reset the working copy and HEAD to this commit, retaining files changed since that commit in modified stategit reset <commit-hash>
Reset the working copy and HEAD to a prior commit, PERMANENTLY ERASING ALL CHANGES SINCE THAT COMMIT (this is useful if you want to drop all modified and staged files versus the last commit by resetting to HEAD itself, but otherwise you should NOT run this willy-nilly. Ask someone experienced before you do this.)git reset --hard <commit-hash>
Reset the working copy and HEAD to a prior commit, allowing you explore the repo as it was at this point in time. This is detached HEAD mode, meaning HEAD is not pointing to the latest commit of a branch. Thus, do not make changes. Create a branch off of the commit if you need an actual working copy.git checkout <commit-hash>
Reset the working copy and HEAD to the latest commit of a branchgit checkout <branch>
Stage a filegit add <files>
Unstage a staged filegit reset HEAD <files> (note how this is a special case of reset above)
Commit all staged filesgit commit -m <Message> (please use commit messages)

Working with remote servers

You want toType
Copy a remote git repo to your computer, setting repo-url to the remote name origingit clone <repo-url>
Make your local git aware of branches on the server, and their states. Use this to “refresh” a repo (note this does not change your local branches, but simply makes you aware of if yours are outdated or not)git fetch <remote-name>
Same, but delete all local branches that have since been deleted on the remotegit fetch <remote-name> --prune
Update a remote branch that doesn’t exist or is directly behind yoursgit push <remote-name> <branch-name>
Update your local branch with commits the remote branch has but yours does notgit pull <remote-name> <branch-name> (this may cause merge conflicts!)
Delete a remote branchgit push <remote-name> :<branch-name>

Branching

You want toType
Make fork of the commit tree at your current HEAD. This could be any commit, so you could theoretically go back to an old commit and branch off that.git checkout -b <new-branch-name>
Switch to an existing branchgit checkout <branch-name>
Delete a branch locallygit branch -d <branch-name>
Force-delete an unmerged branch locally (has commits that will be lost by the delete)git branch -D <branch-name>
Show all branchesgit branch
Show all branches including remotegit branch -r
Combine a branch with the current one, merging its commit tree directly into the current onegit merge <branch-name>

Working with others

Say we are on branch main. Alice makes some changes to foo.txt, and commits it. Bob makes some changes to the file and commits as well. One of them will push first, then the other will then have to pull and then push.

There are two scenarios:

  • Alice and Bob edited completely separate parts of the file.
    • Recall that commits are simply recordings of what’s changed (diffs). If the two commit do not overlap, then it will cleanly be pulled and then the push will succeed.
  • Alice and Bob edited the same region
    • On pull, we enter what is called a merge conflict state. The affected file will gain some markers to guide you to the problem and how to fix it.
This is sentence 1.
This is sentence 2.
<<<<<<< HEAD
This is the awesome and stupendous sentence 3.
=======
This is the amazing and glorious sentence 3.
>>>>>>> <remote>/<branch>
This is sentence 4.

If you are the person who has not pushed, you will need to look carefully at what is different. Your version is bounded by <<<<<< and ======, their version is bounded by ======= and >>>>>>. Do not just delete one side or the other blindly, you are erasing someone’s changes!

You must consider, semantically, what the other person has changed, then incorporate both of your changes together into one copy. This will often involve discussing the work with the other person. A resolved version of the above example would be as follows:

This is sentence 1.
This is sentence 2.
This is the awesome, stupendous, amazing and glorious sentence 3.
This is sentence 4.

Then, you must stage and commit the fixed file. Finally, push it.

Tips

  • Often you’ll find yourself switching back and forth between branchA and branchB. Rather than typing git checkout branchA, you can use the common command line dash (-) argument to indicate to return to the previous branch, i.e. git checkout -. This tip works with git merge as well.
  • In order to add all changes in a directory, you only need to git add <dirname> for that directory. For the current directory, use git add .. Note that directory adds are recursive and might include many more files or changes than you intend.
  • To quickly make a change unrelated to current changes in your local environment you can git stash your current changes. This basically sets your local changes aside while you do the quick work. After committing the other changes, you can run git stash pop to get your stashed changes back.
  • git status. This will tell you what changes are on your system, what is staged for commit, etc. Any time you are in doubt about the current state of your working set, run this command.
  • git diff. This will show what is different between what is staged (or HEAD if nothing is staged) and the current state of your machine. This is another powerful tool prior to commit to make sure you aren’t committing sensitive information or debug statements.