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
Introduction Sequence - A nicely paced introduction to the majority of git commands
Introduction to Git Commits
Git commits are lightweight snapshots of a project you are working on, and switching between them is fast.
Each time we do a git commit we create a new snapshot that is tied to a parent commit.
Make two commits to complete this level.
Solution:
git commit git commit
Branching in Git
Branches are pointers to commits. "Branch early and branch often." A branch essentially says "I want to include the work of this commit and all parent commits.
Make a new branch called bugFix and switch to that branch.
Solution 1:
git branch bugFixgit checkout bugFix
Solution 2:
git checkout -b bugFix
Merging in Git
git merge creates a special commit that has two unique parents. This allows us to combine the work from two branches into one commit.
Make a new branch called bugFix
Checkout the bugFix branch with git checkout bugFix
Rebasing is a second way of combining work. It takes a set of commits, copies, and then plops them down somewhere else. The commit log / history of a repo will be alot cleaner if only rebasing is allowed.
Checkout a new branch named bugFix
Commit once
Go back to main and commit again
Check out bugFix again and rebase onto main
Solution:
git branch bugFixgit checkout bugFixgit commitgit checkout maingit commitgit checkout bugFixgit rebase main
Ramping Up - The next serving of 100% git awesomes-ness. Hope you're hungry
Detach yo' HEAD
HEAD is the symbolic name for the currently checked out commit. HEAD (almost) always points to the most recent commit which is reflected in the working tree. Normally HEAD points to a branch name, like bugFix. Detaching HEAD just means attaching it to a commit instead of a branch.
git show HEAD will show you where the HEAD is currently pointed. Detached HEAD just means HEAD does not currently point to the most recent commit.
To complete this level, let's detach HEAD from bugFix and attach it to the commit instead. Specify this commit by its hash. The hash for each commit is displayed on the circle that represents the commit.
Solution:
git checkout C4
Relative Refs (^)
git log is what we will use in the real world to see what our commit tree looks like. Relative refs make it easier to move up or down a relative number of times in the commit tree. ^ moves up one level in the commit tree and ~<num> moves upwards the number of times specified.
To complete this level, check out the parent commit of bugFix. This will detach HEAD.
You can specify the hash if you want, but try using relative refs instead!
Solution 1: (relative ref)
git checkout bugFix^
Solution 2: (relative ref)
git checkout bugFix~1
Solution 3: (relative ref)
git checkout C4^
Solution 4: (direct hash)
git checkout C3
Relative Refs #2 (^)
A common use of relative refs is to move branches around You can directly reassign a branch to a commit with the -f option: git branch -f main HEAD~3 will force the main branch to 3 parents behind the HEAD.
To complete this level, move HEAD, main, and bugFix to their goal destinations shown
git reset reverses a change by moving a branch backwards in time as if the commit never happened. Open question - what happens to the commit that got erased? Will it still show up if you run git log? Answer: It does not show up in git log anymore, but it seems to still exist, you can still check it out and it comes back to life. This method works find if you are just working locally, but not so good if you are collaborating with others using a remote repo.
git revert solves that problem. This allows us to reverse changes and share it with others.
To complete this level, reverse the most recent commit on both local and pushed. You will revert two commits total (one per branch).
Keep in mind that pushed is a remote branch and local is a local branch -- that should help you choose your methods.
Moving Work Around - "Git" comfortable with modifying the source tree :P
Cherry-pick Intro
git cherry-pick <commit1> <commit2> <...> says you want to grab a series of commits and copy it below your current location (HEAD)
To complete this level, simply copy some work from the three branches shown into main. You can see which commits we want by looking at the goal visualization.
Solution:
git cherry-pick C3 C4 C7
Interactive Rebase Intro
git rebase -i will let you reorder the sequence of commits
Done
A Mixed Bag - A mixed bag of Git techniques, tricks, and tips
Grabbing Just 1 Commit
Let's say you are debugging a problem, you go back and add some print debug statements and print statements. Each one of those has their own commit now. Now you solve the problem and you just want your bugFix commit back into the main branch without bringing along your debug commits. That's the use case for this problem. Two potential solutions are suggested: git rebase -i or git cherry-pick.
Solution using cherry-pick
git checkout maingit cherry-pick bugFix
Solution using git rebase -i
git rebase -i c1 // delete commits c2 and c3git branch -f c4 main'
Juggling Commits
Another use case that happens commonly is we need to change a commit way back in our commit history.
The section utilizes git commit --amend. A good explanation of that command is at the Pro Git Book. This is useful for making a small change to your most recent commit, like modifying the commit message.
Here is the problem:
We will overcome this difficulty by doing the following:
We will re-order the commits so the one we want to change is on top with git rebase -i
We will git commit --amend to make the slight modification
Then we will re-order the commits back to how they were previously with git rebase -i
Finally, we will move main to this updated part of the tree to finish the level (via the method of your choosing)
There are many ways to accomplish this overall goal (I see you eye-ing cherry-pick), and we will see more of them later, but for now let's focus on this technique. Lastly, pay attention to the goal state here -- since we move the commits twice, they both get an apostrophe appended. One more apostrophe is added for the commit we amend, which gives us the final form of the tree
git rebase -i C1 git checkout newImage git commit --amend git checkout captiongit rebase -i C1 git branch -f main C3 git checkout main
Juggling Commits #2
The reordering done in the prior section can cause rebase conflicts, so we can use git cherry-pick to avoid those.
git cherry-pick will plop down a commit from anywhere in the tree onto HEAD
The problem: So in this level, let's accomplish the same objective of amending C2 once but avoid using rebase -i. I'll leave it up to you to figure it out! :D
My solution used 3 commands, their solution used 4 commands. That's a little odd that it worked. It didn't require me to use the git ammend command which I thought I might have to use.
Git Tags
Branches are useful but they are mutable and often changing. Tags are a way to (almost) permanently mark certain commits as milestones.
Solution:
git tag v0 c1git tag v1 c2git checkout v1
Git Describe
git describe will tell you where you are relative to the closest anchor.
Rebasing
Branches
Man, we have a lot of branches going on here! Let's rebase all the work from these branches onto main.
Upper management is making this a bit trickier though -- they want the commits to all be in sequential order. So this means that our final tree should have C7' at the bottom, C6' above that, and so on, all in order.
Solution:
git rebase c6git checkout c3git rebase c2'git checkout c7git rebase c3'git checkout c7'git rebase -i c0git branch -f main c7''
Multiple parents
The ^ operator specifies which parent reference to follow from a merge commit.
To complete this level, create a new branch at the specified destination.
Obviously it would be easy to specify the commit directly (with something like C6), but I challenge you to use the modifiers we talked about instead!
Solution:
git branch bugWork main~1^2~1
Alternate solution but not using the operators taught in this lesson:
git branch bugWork C2
Branch spaghetti
WOAHHHhhh Nelly! We have quite the goal to reach in this level.
Here we have main that is a few commits ahead of branches one two and three. For whatever reason, we need to update these three other branches with modified versions of the last few commits on main.
Branch one needs a re-ordering of those commits and an exclusion/drop of C5. Branch two just needs a pure reordering of the commits, and three only needs one commit transferred!
We will let you figure out how to solve this one -- make sure to check out our solution afterwards with show solution.
Solution:
Did it in 12 steps, but need to revise it down.
First did three git commit --amends to create three branches.
Then use git cherry-pick to move commits under the right branches. Then git rebase-i to reorder the branches. Then git branch -f to get the branch labels to the right commits.
Push & Pull -- Git Remotes!
Clone Intro
Git Remotes are a great backup tool and they allow us to easily collaborate with others on projects. It's important to understand the underlying structure of how remotes work.
Solution:
git clone
Remote Branches
Git automatically sets the name of your remote to be origin. In this tutorial we will use o as a shorthand for origin.
To finish this level, commit once off of main and once after checking out o/main. This will help drive home how remote branches behave differently, and they only update to reflect the state of the remote.
Solution:
git commitgit checkout o/maingit commit
Git Fetchin'
In this lesson we will learn how to fetch data from a remote repository -- the command for this is conveniently named git fetch.
git fetch essentially brings our local representation of the remote repository into synchronization with what the actual remote repository looks like (right now).
git fetch doesn't change anything about your local state, it just downloads the updates.
Solution:
git fetch
Git Pullin'
The workflow of fetching commits from a remote and then merging them is so common there is a single command that does both: git pull
Solution:
git pull
Faking Teamwork
Go ahead and make a remote (with git clone), fake some changes on that remote, commit yourself, and then pull down those changes. It's like a few lessons in one!
Solution:
git clonegit fakeTeamwork 2git commitgit pull
Git Pushin'
git push is the opposite of git pull. It allows you to get your code onto the remote to share with the rest of the team. The default behavior of git push with no arguments depends on the settings called push.default.
Solution:
git commitgit pushgit push
Diverged History
The big challenge with pulling and pushing comes when we have a diverged history, meaning someone else contributed some code to a remote that conflicts with code you are working on. In this case, git won't allow you to git push your code if it conflicts with something that someone else wrote. To resolve this, you must base your work off the most recent version of the remote branch. One solution is to do a git rebase before pushing. You can also do the same thing with a git merge command instead of git rebase. Or an even faster way is via git pull --rebase.
In order to solve this level, take the following steps:
git clonegit fakeTeamwork 1git commitgit fetchgit rebase o/maingit push
Locked Main
If you work on a large team, you generally can't push directly onto the main branch. The solution is to create your own branch locally, make your changes, then push that change to the remote using a pull request.
Solution:
git branch featuregit checkout featuregit branch -f main c1git push
To Origin and Beyond -- Advanced Git Remotes!
Push Main!
This level is pretty hefty -- here is the general outline to solve:
There are three feature branches -- side1 side2 and side3
We want to push each one of these features, in order, to the remote
The remote has since been updated, so we will need to incorporate that work as well
Remote Tracking
Your local main branch doesn't always have to be linked to the remote main branch, although this is the common default setup.
If you want to do something different you create a new branch and point it to whatever remote you want:
git checkout -b totallyNotMain o/main Creates a new branch named totallyNotMain and sets it to track o/main.
Another method is to just update the remote tracking on an existing branch with this command:
git branch -u o/main foo
and if foo is the currently check out branch, we don't even need to specify it:
git branch -u o/main
Ok! For this level let's push work onto the main branch on remote while not checked out on main locally. I'll let you figure out the rest since this is the advanced course :P
Solution
git checkout -b side o/maingit commitgit pull --rebasegit push
Git Push Arguments
git push can take arguments in the form of: git push <remote> <place>
An example: git push origin main, we are telling git what branch to look at to determine where the commits will come from, and where they are going to. Since we specified main as the parameter, git totally ignores where we are checked out when we run this command.
Ok, for this level let's update both foo and main on the remote. The twist is that git checkout is disabled for this level!
Note: The remote branches are labeled with o/ prefixes because the full origin/ label does not fit in our UI. Don't worry about this... simply use origin as the name of the remote like normal.
Solution
git push origin foogit push origin main
Git Push Arguments - Expanded
If you wanted to push some commits from one branch to another branch and they don't have the same name, you can use git push origin <source>:<destination>. This is known as colon refspec, and refspec is just another word for a location that git can figure out. You can even specify the name of a new branch on the remote and git will create it for you.
We can use relative references like this: git push origin foo^:main. Or if the destination we want to push to doesn't yet exist, we can write: git push origin main:newBranch
For this level, try to get to the end goal state shown in the visualization, and remember the format of: <source>:<destination>
Solution
git push origin foo:maingit push origin main^:foo
Fetch Arguments
Fetch arguments can also use the same constructs that are available for the push arguments. We can use colon refspec, the parameter and more.
It you call git fetch with no arguments, it will download all new commits from the remote onto all the remote branches.
Ok, enough talking! To finish this level, fetch just the specified commits in the goal visualization. Get fancy with those commands!
You will have to specify the source and destination for both fetch commands. Pay attention to the goal visualization since the IDs may be switched around!
This solution is 5 steps, they say to try to do it in 4. Maybe combine the last two steps?
Source of Nothing
Git allows you to specify nothing for the parameter when pushing or fetching. Pushing nothing to a remote branch will delete it.
Fetching nothing will create a new branch locally though.
This is a quick level -- just delete one remote branch and create a new branch with git fetch to finish!
Solution
git fetch origin :bar git push origin :foo
Pull Arguments
git pull is really just shorthand for git fetch followed by merging whatever you just fetched. So git pull arguments are pretty much the same as git fetch arguments.
git pull origin foo is the equivalent to:
git fetch origin foot; git merge o/foo
and
git pull origin bar~1;bugFix is equal to:
git fetch origin bar~1:bugFix; git merge bugFix
Ok to finish up, attain the state of the goal visualization. You'll need to download some commits, make some new branches, and merge those branches into other branches, but it shouldn't take many commands :P