Git Calisthenics

Work through every situation you're likely to see over the next few months of using Git.

Scroll down...

Content

Resources

Comments

calisthenics

In this assignment, you'll have the chance to practice what you've just learned by using Git to step through a typical workflow. You'll set up a simple repository, push it up to Github, make changes, work with branches, and handle a merge conflict. All-in-all, a good day's work.

Refer to the previous lesson for the commands that you'll need to use. Try to think through conceptually what you're doing before just copy-pasting commands.

Warmup

  1. For starters, do the quick exercises over at Try Git.

Stretch

When you're creating a brand new project, you'll typically go through the same steps. Get some practice by following these instructions. Can you remember the commands that correspond to them?

  1. Create a new folder from the command line called test and go into it.
  2. Initialize your Git repo inside that (now empty) folder.
  3. Check the status -- you should see nothing too interesting:

Git status for empty folder

  1. Create an empty text file called README.txt.
  2. Add that file to staging.
  3. Check your status:

Git status with README

  1. Commit your changes with the message "initial commit". Check the status:

Git status after commit

  1. Look through your history to see the commit message show up, along with some more info about the commit:

Git logs after commit

That's enough warmup.

Get Gitting!

  1. Open your README.txt in your text editor (from the command line!). Handy trick: you can pass your text editor a directory instead of just a filename to open the whole thing.
  2. Add the line "Hello World!" to the file and save it.
  3. Stage and commit your changes with the message "add a friendly hello".
  4. On the next line, add "Knock, knock.", stage, and commit with the message "add the knocker to the joke". If you want to combine a git add . and git commit -m into one line, use $ git commit -am "your message". Just remember that, if you've deleted files, they won't be pulled in (this is the shortfall of git add . vs git add -A, which includes everything).
  5. Add the line "Who's there?", stage, and commit with the message "add the responder to the joke". This should be pretty straightforward now.
  6. Check your log again, which should include all your commits thus far:

Git logs

Go Remote

Now it's time to play around with getting your repo up to Github and making changes to it directly on Github. Of course, if you do that, you'll need to bring the two back into alignment...

  1. Create a new repository on Github. Do not check the checkbox "Initialize with README".

Create a new Github Repo

Create a new Github Repo -- Page 2

  1. Look through their instructions on the next page. You've already done several of the things they mention, but you'll still need to add that repository as a remote so you can push your local repo up to it. Do that now, and call it origin.
  2. Check your remotes, now they should show:

Git remotes

(Again, don't worry if yours uses https: instead of git:)

  1. Push your local repo up to Github.
  2. Refresh your repo's page on Github and you should see what you've written show up. Anything in a file named README.txt or README.md (a different text format that sort of combines HTML and text) will be displayed by default on your Github repo's page.

  1. Now you'll edit the README file on Github (a handy feature they have) and pull down your changes. So, still on Github, click on the link to your README file. Then select the "Edit" option from the buttons along the top of the file:

Click the README link

Edit a file on Github directly

  1. In the edit window on Github (which can be helpful for making quickie changes to your files), add the line "Git." to your joke. At the very bottom, you'll see the button to commit your changes. First, add a commit message that says "Add response from the knocker" and then click "Commit".

Edit on Github

Commit directly on Github

  1. What you just did is basically a graphical version of what you've been doing on your local computer until this point. When you make the commit we just did on Github, changes are only reflected on the Github version of your repo. So now your Github version is ahead of your local version! You won't use this feature much, but it's useful to illustrate how your origin repo on Github can get ahead of your local one. You can see the changes reflected on the Github README and also in the list of commits (reached by clicking the "commits" link at the top of the repo on Github):

New changes reflected on Github

Commit history on Github

Note that I've got a couple extra meaningless commits in there so don't worry that you don't have them

  1. So now your local repo is one commit behind your remote Github repo. If you tried to push other changes up to your Github repo now, it'd throw an error at you. You need to bring the two back into alignment. Pull the changes down to your local repo:

Pulling changes from Github

  1. Check your log to see that your latest commit is now showing up in your local:

Updated git logs

Branch Out

Now you'll get the chance to see branches in action and merge them together.

  1. We're going to finish off the knock-knock joke but we realize that we should have been treating it like a brand new feature all along. Let's make a new branch for it! Create a new branch called knock-knock. Check your status and you'll see that everything is the same. Any changes we make from here will be saved to this specific branch and won't show up in master until we merge it back in.

Git branch with no changes

  1. If you're using a modern text editor, your open README.txt file should already have updated to show the new line we just pulled from Github. If not, you may need to reload the file. Now continue the joke by adding the line "Git who?", staging it, and committing it with the message "continue the knock-knock joke".
  2. Now you've got a similar situation to the one we had with Github and your local repository -- your knock-knock branch is one commit ahead of your master branch. Verify this by checking your git log and then switching back over to the master branch and also checking the log. You can also see, when you switch back to master, that the new line isn't included in the file yet. It's like you never typed it. That comes in handy when you're working on code for a feature and it all goes to hell and you just want to blow it away completely -- you can erase the feature branch like it never existed.
  3. Now that you're on master, merge your knock-knock branch into master. Verify via the log and in your text editor that the next line of the joke is now a part of master.

Create (and Resolve) Conflict

Now we'll walk through solving a merge conflict. They don't happen often, but they can panic newbies because you feel stuck in the middle. It's not a big deal, you'll see.

  1. Let's finish the joke. Still in the master branch, add the final line "Git on with the assignment!", stage, and commit with the message "finish the joke".
  2. Let's say it's been a few days and you forgot that you finished the joke already. Switch over to the knock-knock branch. Verify that the joke has NOT been completed yet on this branch.
  3. Add a different final line that says "Git this joke over with.", stage, and commit with the message "finish the joke even better".
  4. Now that we've finished the joke, let's complete this "feature" by merging it back to the master branch. Although we could just merge knock-knock directly into master like we did before, it's actually conventional to do the opposite -- merge master into knock-knock and, once all conflicts are resolved, merge knock-knock back into master (which won't have any conflicts anymore). This is best practice because you don't really want to be fixing a bunch of merge conflicts on your master branch if you're working with other developers or with a big code base. Anything you merge into master should already be up-to-date and clean. So that's what we'll do here. Let's get the conflicts started -- merge master into knock-knock...

Git branch merge conflicts

  1. Okay, not a big deal, it's telling us that we've got a conflict and it has "unmerged paths" so far because they need to be resolved first. It even tells us that we need to "fix conflicts and then run git commit", thanks! So how do we fix the conflicts? The simple-seeming way is to just refresh your text editor and look at the merge markers (since it tells you exactly which file has the conflict):

Git merge conflict markers in Sublime Text 2

  1. You can see that the HEAD ending to our joke (HEAD is the branch we're currently sitting in) is on top and the ending coming in from master branch is below it. To resolve this, simply delete the line you want to get rid of and delete all three merge markers. Once there are no merge markers left, save and quit the file, stage it and commit the result. Your merge is now complete. Pretty painless, right?

Git merge conflict resolution

  1. Finally, now that your knock-knock branch is up-to-date with master, jump back over to master and merge in your knock-knock branch. It should go through without any issue -- your most recent commit that resolved the merge tells Git that everything's been taken care of.
  2. Push your master branch up to Github and view the result:

Github resolution of the merge conflict

Recap

We did a lot of different things in this assignment and covered just about every situation you're likely to face with Git in the next several months. If you're still really unsure of what's going on, try doing it again from scratch. Again, though, you'll get so familiar with this stuff that it'll become second nature. This stuff will be particularly relevant again in the upcoming mini-course on Coding.

You've probably got a few lingering questions which are outside the scope of this particular assignment, so check out the Resources tab for more explanation.



Sign up to track your progress for free

There are ( ) additional resources for this lesson. Check them out!

See the lesson on Git for a comprehensive list of resources.

  • How do merges actually work? This Git-SCM article explains it
  • How do pushes and pulls actually work? A pull request is actually doing two things -- it's fetching your remote branches down onto your local machine and then mergeing them into your current branch. It takes a minute to understand, but it's a pretty nifty process. Atlassian's tutorials cover fetching and pulling.

Mergetool Alternative

There's an alternative to manually opening up each conflicting file to remove the conflict markers -- you could try using the Git mergetool. Consider it an intermediate alternative for sure (I wouldn't dabble with it right away) but it's really helpful for larger merges where you've got several files that have conflicts.

The mergetool basically cycles through each conflicting file and opens it up in your text editor for you so you don't need to go digging for them yourself. You'll need to set up its configuration to use your preferred text editor (otherwise you might get stuck in Vim) and to not keep a bunch of backup files lying around, but after that it's a timesaver.

To fire up the mergetool when you're in the middle of a conflicted merge, just type $ git mergetool and it'll bring up the first conflict:

Git mergetool screenshot

Press ENTER to open the file up in your text editor and do exactly what you did before -- remove the merge markers and fix any offending lines of code. As soon as you save and close the file, the mergetool will bring up the next conflict for you to check out. Once you've gotten rid of any conflicts, do the normal stage-and-commit and you're good to move on.

NOTE: You'll want to set your editor to be your mergetool's default text editor (otherwise you'll be stuck in Vim land again). To do so, search "set YOUR_EDITOR as git mergetool".

Another helpful configuration is to remove the messy merge files that otherwise get leftover during a merge. To do so, use:

git config --global mergetool.keepBackup false

Setting Sublime Text 2 as Mergetool

You can set Sublime Text 2 to be your default merge tool editor by visiting this Coderwall snippet, which has you do some quick command line config:

git config --global mergetool.sublime.cmd "subl -w \$MERGED"
git config --global mergetool.sublime.trustExitCode false
git config --global merge.tool sublime

Sorry, comments aren't active just yet!

Next Lesson: Test Yourself