Code School: Mastering GitHub
- Fork Based Workflows
(Song) She'll clone and fork your repos faster than you can blink And then tag push and pull requests while pouring a drink She started wiki zen pages to promote her skills But it's the branching and the merging Which will pay all the bills Your only chance to find her is the user workflow Commit to her release and you can access control You'll be pushing past security to join her at the club Just to catch a glimpse of her mastering GitHub - You're watching level one of Mastering GitHub. I'm Peter Bell. In this course, we're going to be looking at the process of using GitHub to collaborate effectively with your team. GitHub is more than just a place to store your Git repositories. It's a place for sharing your code, discussing it with your team members, and even doing lightweight code reviews. There are lots of different ways that you can work with Git and tools like GitHub but we're going to be focusing on proven best practices for using GitHub to collaborate effectively. We're going to make some assumptions at the start of this class. We're going to assume that you're already familiar with the basics of adding and committing files to a Git repository, using feature branches effectively, branching, merging, rebasing, and dealing with conflicts if you've got a merge or rebase conflict. Let's start by making sure you have your Git configuration set up the way you need it for the rest of this course, and hopefully, you'll learn one or two tips or tricks along the way. As we go through this course, make sure to keep a Console window open and follow along with the commands. That way, you're going to be able to get some hands-on experience plus the challenges are going to be in the Console as well, so you'll be there and ready to complete them. There are three different levels of configuration in Git. You can configure at a local, global, or system level. Most of the configuration you're going to be doing is at a global level for all the respositories that you work on in this machine. But, sometimes, you might want to set a local configuration. For example, if you wanted to override your email address. If you're account leader in most of your work for a company but you're working on one open source project, you might want to git config --local your user.email just for that open source project. And occasionally, you might want to configure something at a system level which is for all the users of the system irrespective of who they're logged in as. So for example, you might want to set the system color.ui to true for all of the users of the system because it's something that everyone's going to need to have configured. So let's start quickly by checking your global configuration. If you git config --global user.name, that's going to get and return your username, and if you git config --global user.email, that's going to display your currently configured global user email. If you're happy with those, you can leave them as they are. If not, you can actually jump in and change them just by using the same command but by putting a value on the end. There are two ways you can look at your global configurations. You can certainly git config --global --list to use Git to list all of your global configuration settings. But the other thing you could do is you can actually just look at the underlying configuration file. If you just cat to catalog or output, the contents of the ~/.gitconfig file, that will take this file from your home directory and show all of your global Git configuration settings. And in fact, you can even edit this file using a text editor. Let's look at an example of that. Here, we're going in to our global gitconfig, and let's say we wanted to change our email address. You just go into that, change it, save the changes to your file, and then when you look at your gitconfig at a global level for your user email, you'll see that it's now being changed. Viewing local configuration settings is very similar to viewing the global ones. You could gitconfig --local --list to list them using Git or you could just look at your local git configuration file which is in the .git directory in a file called config. And again, this is something you could edit using a text editor if you wanted. Have you ever had the experience that it looked like somebody had changed every single line in three or four different files? But when you looked at the changes they made, they didn't actually seem to have changed any of the content. This can occur when you have people working on different operating systems and perhaps, you've got line feeds at the end of each line and perhaps they were using windows and added carriage returns as well. One of the most important configuration settings you can use is autocrlf or auto carriage return line feed which allows you to solve this problem. Depending on your operating system, these are the commands you're going to want to run to make sure you don't run into that problem. Another important setting, especially if you're not on Git 2.0 or later yet, is configuring your push default. Historically, the push default was always set to matching, which meant that whenever you pushed to a remote server like GitHub, it would push all of the matching branches. You might push changes to three or four branches without realizing what you were doing. You probably want to configure your push default to simple, which means it's only going to push the changes on the branch you're currently on, which is a much more intuitive choice and that's actually now the default in Git 2.0. Another important configuration setting is to configure your pull default. Often, what people would do is they will git pull and because the pull is a fetch plus a merge, what it does is it creates these merge commits where it's taking their local commits with whatever commits they downloaded and adding this curious merge commit that really adds no useful information to the repository's history. You're usually much better to rebase on pull. So to do a git pull --rebase. The problem is it's sometimes hard to remember to do that on a regular basis. So if you want to make sure that your pull defaults are configured correctly so that you always fetch and then rebase, what you want to do is git config --global pull.rebase to true and this means for all of your repositories, it will rebase when you pull instead of merging. One problem that can occur is when you need to resolve the same merge conflicts multiple times. Perhaps if you are cherry-picking a commit to multiple long-running release branches, or perhaps if you are rebasing regularly or merging in and then backing out a merge after integration testing. Luckily, there's a configuration option that can save you a lot of trouble doing this. With ReReRe, or Reuse Recorded Resolution, what you can do is ask Git to capture every time you resolve a merge conflict, and then in the future, if you have exactly that same merge conflict, it will remake the same change but still give you a chance to review it just to make sure it's acceptable. So I'd strongly encourage you to configure ReReRe and enable that and set that to true so that you can take advantage of this feature. Finally, if you're running an old version of Git, 1.84 or earlier, it's important to configure at a global level to set the color.ui to true. This is what gives you the green and red coloration in Git so that you can see more easily what's going on. There are some very powerful options in Git, but some of them can require a lot of typing. Aliases allow you to create your own custom commands that do just what you want, and there's a couple of aliases we're going to recommend that you use throughout this course. The first alias we're going to recommend is git s. If you look at a git status, you'll notice that it takes up a lot of space to show you information, whereas if you do git status -s or silent mode, it gives you just the information you need most of the time in much less space. So if you git config an alias called s for status -s, that will allow you to output status in silent mode just by typing git s. Git log is a great command, but by itself, it doesn't really give a very useful output because it takes lines and lines of information just to show you the last two or three commits. Wouldn't it be great if we had a command like git lg, let's say, which wouldn't be too much typing, that would show us every commit when it's online, that would decorate those commits with things like the head, the branches and perhaps even tags, and it would show us things like the graph as well, so we could see what commits were made on what branches. Well we can do that if we create a git configuration option with an alias of lg that is a log with the oneline, decorate, all, and graph options set. Git configurations are specific to the machine you're on. They don't get shared when you push, pull, or clone a repository. Because of that, it's important to figure out how you do want to share some settings between team members, whether it's the same aliases or making sure that everyone rebases on pull. There are two common patterns for doing this. One is to just put your configuration options in a wiki so people can cut and paste them, and run those configuration commands whenever they set up a new machine. The other option is to create a repository for your dot files, where you can put your .gitconfig and any other important dot files, and share them easily between members of your team.
Forking and Cloning
Welcome back. In this section, we're going to go through forking and cloning. When you create a new repository on GitHub, the first thing you're going to want to do is clone that, so that you're downloading a copy of the repository to your local machine, and then you can make changes locally and push those back up to GitHub. If someone else has created a project on GitHub, and they've added you as a collaborator, again, you can just clone a copy of the repository, make any changes you want, and push them back up because they've given you permission to do so. However, if someone's created a public repository on GitHub, and they've not added you as a collaborator, you can still clone that repository to make a local copy. You could use the files. You can commit and make changes locally, but you're not going to be able to push your changes up to GitHub because you don't have the permission to do so. So the question is how do you collaborate on a repository that you don't have permission to push to? Well the answer is you create a fork of the project. When you create a fork, you're creating your own copy of the repository still up on GitHub, but under your username or organization name, if you're running an organization, and what this does is it creates a copy on GitHub that you have full permissions to. So now you can then clone that copy, make changes locally, commit them, and push them up to your fork. Notice that I'm looking here at the dojo_rules repository, which is owned by the deadlyvipers. If I want to make a change to this repository, I'm going to have to fork it so that I have my on copy. So let's look at that process. I'm going to go click the Fork button in the top right. Then I'm going to choose where to fork it to. In this case, I'm going to fork it to my personal account. Once the fork's made, notice that now there's a new copy of the repository at my username slash repo name. And now that I've forked it, I just need to clone it to download it to my laptop, so I'm going to copy the clone URL, go into a terminal window, and clone the repository. And now, I can go in here and make changes. I could open up a file, and I could make some changes to edit that file. Once I've made my changes, I can add and commit those to Git, and because I'm pulling from a fork, I can now push my changes back up to my fork, and I'll see that when I go back to the fork, and look at the list of commits, I'll see my commit right there.
Submitting a Pull Request
So you were trying to collaborate on a repository that you didn't have permissions for. So you made a fork, so there was your copy on GitHub. You cloned that down to your laptop, made the changes, and pushed them back to your clone. But wouldn't it be great if you could somehow get the changes or improvements you've made back into that original project? Well you can, and the mechanism to do that is a pull request. As we can see here, this is a case where there was an original project, you made a fork of it, you cloned it down to your laptop, and you've pushed your changes back up. When you send the pull request, the owner of the original repo is then notified so that they can go and check the status of your pull request and decide whether to accept it or not. You can think of a fork as a branch. So in this diagram, you can see that we've forked the codeschool repo and created our own copy of that, and we've got our master branch that we're making certain commits to, and then at the same time, commits are being made to the master branch of the codeschool repo. The pull request is us requesting that the changes on our master branch get merged in to the master branch in a codeschool repo. And if a pull request is accepted, that's exactly what it will do. It will create a merge commit. So let's look at the process of creating a pull request. In this case, I'm going to request that the changes I made to my fork, my copy of the dojo_rules repository, get pulled in to the original deadlyvipers repo. So the first thing I do is, in the top right hand corner. there is a Pull Request button, so I'm going to click that and then click New pull request when that appears. You'll notice that I am requesting the changes from my master branch to be merged in to the deadlyviper's master branch. I click on the Create new pull request button, enter any information, and then click on the Submit pull request. And here we are with a created pull request. Notice that we are on the deadlyvipers' copy of the repository because that's where the pull request was created, because we are asking them to accept the changes into their copy of the repository. The next time the deadlyvipers logs in, they're probably going to look through a list of the pull requests they received, including ours. On a public GitHub repo, anybody can review and comment on a pull request. They can check out your branch, run the code, and perhaps run some tests against it to make sure it's running, and if they have permissions, they can then accept the pull request and merge it in to their repository. Let's imagine somebody comes across your pull request, and they click on the pull request, and decide to go look at your code, but this person thinks you've gone too far. What they can do is they can actually make a comment right in the pull request, suggesting that you've gone too far, and submit that change. When they do so, you're going to get an email notification. When you do that, if you agree with them, you can then go back into a terminal window, edit a file, and make a change that seems to be consistent with their feedback. You can then add and commit that change, and push it up to GitHub, and because pull requests point to a branch, not a specific commit, that will automatically get added to the pull requests, so now your new commit becomes part of the pull request as soon as you push it to your fork. They can then look at your changes, and if they're comfortable with them, they can make a comment saying that they are plus one, and that they think you should ship this, and when you get that, depending upon the rules that you use in your team for maybe one or two other members of your team, you can then click on the button to merge the pull request. And now we can look at the commit history in the deadlyvipers' copy of the dojo_rules repository, and see the commit we made and the merge commit that closed the pull request. And you'll notice that the merge commit even has a reference back to the pull request, so we can link back to the pull request and see any discussion that might have occurred while we were working on this functionality.
Updating Your Fork
When you're collaborating using forks, it's important to update your fork to capture changes that have been made by other collaborators. In this section, we're going to explore how to do that. Let's say that we have two developers that want to collaborate on a single repository using forks. We're going to start with the initial repository. We're going to call that the upstream because both of the developers are going to create downstream forks of that, so that they have their own copy of the repository. And then both of the developers are going to clone those repositories to their individual laptops. They're going to do coding, add and commit their changes, and push those changes up to their forks. Then both of them are going to submit pull requests with their changes which eventually will get accepted and merged into the upstream repository. Well the problem is each developer now only has their changes. They don't have a copy of the changes made by the other developer. Because those changes are only on the other developer's fork and on the upstream repo. So what they need to be able to do is they have to pull from the upstream repo to be able to get the accepted pull requests made by the other developer to update their fork. So to look at the commands required to do that, the first command is you're going to add a remote using Git, pointing to the upstream repository with the path to whatever that repo is. You're then going to fetch the changes from that upstream repo and merge the changes that were in the upstream master branch with your local master branch in your laptop. And then finally, you're going to push those changes to your fork so that it has all of the changes made by the other developer. This is something you're going to want to do every time a pull request is accepted into the upstream repo. So let's see this in practice. Let's imagine that somebody comes to the deadlyvipers dojo_rules repository, and they make their own fork of the repo, and they decide to make a change. They go to your file, and notice here the Edit button that allows them to make a change right on GitHub, and to commit that change. They go into the dojo_rules file, and they add a simple commit message, and then commit that change. Then they create the pull requests, requesting that this change be merged into the deadlyvipers' copy of the repository. Now let's go in and look at the pull request that they created. Now if I log in as a member of the deadlyvipers, I can go look at their pull request, look at the change they made, and if I'm okay with that, I can merge that pull request in, and I get the chance to type a merge commit message if I want to make it clear what work I was bringing in or why I accepted it. So we merge their changes into the upstream repository and we can see that right here on GitHub. So if we go back to our Console as our original user, remember, this is Peter Bell, who has a fork of the deadlyvipers repo. We git pull, but it doesn't download anything, and when we look at the contents of the dojo_rules file, we see that it doesn't have the change that was accepted and merged into the upstream repo. So to fix this, what we need to do is we need to add a remote. The convention is we'll call it upstream, and we've got to point that to the deadlyvipers' copy of the repository. And then what we need to do is pull those changes down. Now that we've pulled those changes down, you can see that we now have the changed content for the dojo_rules file and the next time we push up to our fork, that will push the changes to our copy of the repository on GitHub as well.
Single Repository Workflows
Single Repository Workflows
(Song) She will clone and fork your repos Faster than you can blink And then tie, push and pull request while pouring a drink She studied Wiki's end pages to prune motor kills But it's the branching and the merging Which will pay all the bills Your only chance to find her is the user workflow Mid to a release and you can access control You'll be pushing past security to join her at the club Just to catch a glimpse of her Mastering GitHub - Fork based collaboration is great for occasional contributors. But if you're working with a team on a regular basis, you're probably going to want to collaborate using a single repository. In this level, we're going to look at how to do that. Let's say you're working with a team of three other people, and you're using a fork based workflow. You're going to have your own fork that you need to set up as a remote to pull from and push to. You're also going to have to set up the upstream as a remote so that you can pull any pull requests that have been accepted from other members of your team. But in addition to those two remotes, you're probably also going to have to add three other remotes for the three other members of your team to pull from their forks. Because, if you don't do that, you won't be able to pull from and download a copy of any changes that they're working on that have not yet been accepted as pull requests into the upstream repo. In practice, this is a lot to keep track of, so most teams instead use a single repository workflow. With a single repository workflow, everyone is working directly with a clone of the same repository on GitHub, no forks required. And because of that, it's very easy to keep things updated. You just have a clone of that single repository on GitHub, and you can pull or push from that to get all of the changes that everyone is working on. However, you have to be careful if you're working with multiple contributors on a single repository. Because if everyone commits directly to the master branch, you're going to run into conflicts on a regular basis. So instead, what you need to do is you need to use a feature branch strategy where everyone is contributing on their own separate feature branches on that single repository on GitHub. This makes it easy for people to contribute to other people's work because all you need to do is fetch the changes from the remote server, look at a list of all your branches doing a git branch -a, and then check out any other branch that any member of your team has pushed up to GitHub. And then, once a feature is done, any member of the team can check it out, make sure that the tests run well and then merge the work into the master branch and push that up to GitHub. Pull requests add another level of collaboration to this process. Rather than having to check out a branch and send emails to members of your team saying "I like this, but could you make a change?" With a pull request, you can have multiple developers collaborating on a branch and commenting on it directly on GitHub. And this is the GitHub flow: where every developer creates their own feature branch; all the developers work on a single repository; and then the developers, when they're ready, create a pull request requesting that the rest of the team review their work and then eventually merge it into the master branch. So let's look at this in action. Let's say we wanted to add a new feature. We would create a branch locally and then go do some coding. We might create a file and populate that with some content. We then add that change, commit it, and push it up to the remote server. And the way we do that is using a git push -u origin branch_name which does two things: it pushes the changes up to a new branch on GitHub with the same name, but it also sets the default upstream for that branch which we can see here in our .git/config file. So in future, if we want to push or pull from that branch, we can do that. Once we're ready to get feedback on this branch, then we go into GitHub and create a pull request. We can select from a drop-down list of all the branches to pick which branch we want to create the pull request on, which branch we're requesting that we merge back into the master branch. Then we create the pull request and wait for feedback from the rest of the team.
Collaborating on Pull Requests
Whether you're just proposing a new potential feature or whether you think your code is ready to merge, there will usually be some kind of discussion or collaboration around most of the pull requests you create. When you're collaborating on a single repository, there's nothing to stop you merging your pull requests in without any feedback from the rest of the team. But don't do it; it's a bad idea. Let's take one more look at the workflow. The first thing you do is create a branch. In this case, we called it f1. And then you make at least one commit on that branch and push it up to GitHub. Once you've got at least one commit, you can now create a pull request to start to get feedback from the rest of your team on the code that you're working on. You can then get comments from different people on the team and, if you want to make changes, you can simply make those changes on the branch, push them up to GitHub, and they'll automatically be added to the pull request. Because pull requests point to the head of the branch not to a particular commit. Once at least one or two people on your team have approved the changes, you or they can then go ahead and merge those changes back into the master branch either by using the web-based interface to merge the pull request or by merging the feature branch locally on the command line and then pushing those changes up to GitHub. There are three types of comments that can be made on a pull request. They can be made at a high level on the pull request itself: "I think this is a great feature." They can be made at a commit level: "Oh, I'm not sure that I agree "with the changes you made to this code." They can even be made at a line level: "I really don't think you should've deleted line 12." Let's look at collaborating on a pull request and see how it works. Anybody on the team can make comments on a pull request. Pull requests are designed to make it easy to collaborate. So one thing you should consider is @ mentioning members of your team using their GitHub user names. That way they'll get notified by email whether you're looking for them to review some of your code or you're providing feedback on changes they've made. The pull request window updates automatically so you can have a close to real time chat with other members of your team as they're making changes. Here you can see that somebody commented on a specific line of code. And if you see a comment that you agree with, you might then want to go back into the command line to make the requested change, in this case, to remove Budd from the kill list. And then as usual, you add and commit your changes and push them to the remote server. And then when we go back into the pull requests, you will see that your changes have now shown up as another commit as part of the pull request. And if your team agrees with the changes you've made, you can then just merge the pull request in so that your changes become part of the master branch, and the pull request gets closed. So let's briefly look at the commands we'd use when reviewing a pull request. First thing we do is git fetch to download all of the latest changes and all of the branches, to have a copy of everything that everyone else has worked on and pushed to GitHub. Then we do a git branch -a to show all the branches, including the remote branches. Then, if there's a branch that you want to work on that relates to a pull request, you can git checkout and it will automatically create a local branch pointing to your remote tracking branch. There you can make whatever changes you want, you can commit them and push them, and now your changes will be part of the pull request that was created by one of your team. So far, we've focused on other people reviewing our work, but often we'll want to review work someone else has been working on. Let's say someone's working on a feature, and we want to see how it's going. Well we can start by viewing the pull request and making some comments online, but eventually we're going to want to checkout and run their code. All we need to do is git pull to download all of the changes that people have been working on. Then we can do a git branch -a to see a list of all of the branches that are there. And we can see that there's an equipment_list branch. So let's git checkout equipment_list so that we can go see and make a change to that branch. In this case, let's add a little more equipment to the list just make sure we're well-supplied for our next mission. We add and commit the changes, push them up to GitHub, and then, if we go back in to GitHub in the pull request, we now see the change that we made to a pull request and a branch that were created by somebody else on our team. Finally, we can make comments, other team members can make comments, and when we're ready and comfortable with the changes made, we can then merge the pull request using GitHub.
Merging Pull Requests
Welcome back. So far, we've looked at the logistics for working with pull requests. In this section, we're going to look at three key considerations that you need to think about every time you're going to merge a pull request. The three key considerations are whether you should use an interactive rebase to simplify your history, whether you should use a rebase to create a linear history so it looks like you worked on one feature at a time, and/or whether you should use fast-forward or recursive merges when you're merging feature branches into your master branch. Careful use of interactive rebases can do a great job of simplifying your history. Generally, when you're working with Git, you'll be committing every five, ten minutes, and sometimes you just don't need to keep that granularity of information. So before you merge a feature branch in, you should absolutely go back and look over your history and see are there any commits that could be reordered? Maybe where the commit message could be changed, or even where you could squash or fix up a number of commits to simplify history. If you're not familiar with interactive rebase, make sure to checkout Git Real too. It's important to avoid a common anti-pattern which is just taking all of the commits on a feature branch and squashing them into one. Occasionally this can make sense, but most of the time you want to keep a more granular history than that. So just because you decide to do interactive rebases does not mean you should squash every feature branch into just a single commit. The next question is whether you should use a rebase to create a linear history. So instead of it showing the truth where maybe you were working on five or six or ten features at a time, your history will look like your development team only ever started, worked on and delivered one feature at a time . It's not always truthful, but it's generally much more useful to use rebase in this way to give yourself a clean linear history so that you can look back on what you've done and other people can better understand what your team has been working on. And to do that, you just checkout the feature_branch and git rebase master, resolving any rebase conflicts in the same way as you'd resolve merge conflicts, if there are conflicts between the changes on your feature branch and the changes that were made on the master branch. Then the final question is whether you should use a recursive merge or a fast forward merge. The benefits of a fast forward merge are that you get less commits, because the commits from your feature branch are put straight onto the master branch with no merge commits. The downside is it's much harder to tell what commits were made on what feature branch. So generally, I recommend using a recursive merge even if there was no changes on master because you've rebased and you would be able to do a fast forward merge. If you want to make sure that you have a recursive merge, just checkout master and git merge --no-ff, no fast forward, the feature_branch. And that way you'll be guaranteed a merge commit which will make it very clear what commits were made on a feature branch because they won't be added to the master branch, and it will also give you a single commit that you can revert if you want to remove this feature branch from history. To summarize, with fast forward merges, you do get less commits because you don't get the merge commit every time you merge a feature branchette. But I generally recommend to use recursive merges because, firstly, it makes it very clear that every commit was made on a feature branch not on master; and, secondly, it gives you that single commit that you can revert to remove that feature branch from your history. Looking at these three key considerations: When merging pull requests, generally you should interactively rebase to simplify your history, but only removing commits that don't add value when looking at how the project was built. You should definitely consider rebasing to create a linear history so it looks like you only built one feature at a time. And, finally, you should use recursive merges because they provide more clarity about where commits were made and make it very easy to revert a feature branch. So let's look at going through this process end to end. We've got a pull request here with a number of commits that are a little confused. So lets go into a terminal window and we can see here that we've got five commits on the action_plan branch. And we probably don't need that many. So we want to rebase interactive from the Got to kill Bill commit. So let's checkout the action_plan branch, have a look at the log now, and we see now that our HEAD is at 2e03 on the action_plan branch. So now, we can git rebase -i HEAD~5 to rebase the last five commits. Most of the time you'd want to keep a number of these commits. Most of the time you wouldn't squash all of these commits. But in this case, there really was only one substantive thing we did. We built a simple list of people to kill. So let's reword the first commit so that we can change the commit message, and then let's fix up all of the other commits to squash them into that first commit and discard their commit messages. When we're done with this, it will throw us back into our text editor and give us a chance to change the commit message to the one commit we're saving. We put the new commit message in; it continues with the rebase; and now, if we're to look at our git log, we see that there's just a single new commit, d99e, that is at the HEAD of action_plan that has all of our changes. Now we can push those changes, -F. We're going to have to force push them up to GitHub; and then, when we go back into the pull request, we see that instead of five different commits we now see just a single, simple commit for this pull request. So we've done the rebase interactive, and we see in the file it's adding all the content we wanted. Now we want to rebase this against the master branch because we can see that there were some commits on the master branch, and we want to make it look like we didn't start working on the action plan until those commits were finished and merged. So from the action_plan branch we will git rebase master, and that will replay our commits on top of the master branch. So now when we look at the log, we can see that the action_plan branch looks like it was started after all of the other commits on master were finished. And again, you're going to have to git push -f to force this change because we've changed the SHA1 hash of this commit. And indeed we see, when we refresh the page in GitHub, that there is still only a single commit on the pull request, but now it has a different SHA1 hash. Then, finally, what we need to do is git checkout master and then git merge --no-ff our feature_branch. We enter a commit message, and then push those changes to GitHub. And because pull requests are closed when the branch that they point to gets merged into default branch on this repository master, on GitHub the pull request has now been merged and closed. I know that's a lot to wrap your head around, but it's important that you get used to working with these best practices.
Tags, Branches, and Releases
(Song) She'll clone and fork your repos faster than you can blink And then tag, push, and pull requests While pouring a drink She's studied wikis and pages to promote her skills But it's the branching and the merging Which'll pay all the bills Your only chance to find her is to use a workflow Mid to a release and you can access control You'll be pushing past security to join her at the club Just to catch a glimpse of her mastering GitHub. - Welcome back to Mastering GitHub. In this level, we're going to be looking at tags and releases. So far we've talked a lot about how we can use feature branches to build new functionality, but we haven't talked at all about how we can use tags or release branches to manage moving that functionality to production. Let's start by looking at tags. The first question people often ask is when should I create a tag? And the answer is every time you push to production, you should tag that commit. The only exception to this is if you have a continuous delivery environment where every single commit on your master branch ends up in production. It's important to tag every production release so that you know exactly what code has gone to production at what time. There are three different types of tags. Lightweight tags allow you to create a simple, human-readable title for pointing to a particular commit hash. Signed tags allow you to cryptographically sign a tag so you can prove that it was you that made the tag. But most of the time you're going to use annotated tags. What they allow you to do is give a name to a particular commit, but also to capture who created the tag, when they created the tag, and in a description field, explain why they created the tag. So let's look at how we'd use annotated tags. The command you'd use is git tag -a to make it annotated, and then you'd give it a name. In this case, v1.3.2, which is version 1.3.2, with a -m message of whatever the tag message should be. If you leave off the -m, it'll just throw you into your default text editor and you'll be able to create a more comprehensive message there. Once you've created the tag, you then want to push it up to GitHub. This doesn't happen automatically with a push, so you have to do git push --tags to upload any or all of the tags you've created locally to your GitHub repository. A common best practice for naming tags is to use semantic versioning. So you might start with a v and then follow it by three numbers, the major release, the minor release, and the patch version. The major release is to identify substantial changes to the application, often ones that will break backwards compatibility. Minor releases are to capture new user-valued functionality, and patch releases are used for simple bug fixes. Let's look at this in action. If we go to the terminal window and check out our git log, we can see that there was a previous release, ccbc2. Now, let's say that we wanted to tag that. So the first thing we'd do is we would git checkout to checkout that SHA1 hash. And of course we're in a detached HEAD state because we are not on a commit that has a branch associated with it. Then what we can now do is create a tag here, so we just git tag -a, give it a name, and then we can either -m to give it a message or in this case go into a text editor to create as more comprehensive message for the tag. When we go back to the log, we can now see that tag against the SHA1 hash. But when we go up to GitHub and look at the list of releases, the tag isn't there. That's because we've not pushed it up yet. So we go back to the command line, git push --tags to upload any of our tags to GitHub, and now when we look in GitHub, we can see that tag under the releases tab. If you want more information on naming your tags, a great place to go is the semver.org, semantic versioning.org website, that has a lot of information on best practices for using semantic versions for your version numbers.
In the last section, we looked at release tags. In this section, we're going to take a little bit of time to look at where and when it makes sense to use release branches, as well. Whatever happens, you want to create release tags whenever you push to production, and most of the time that's all you need, but occasionally you also need release branches, as well, where you need to make changes to a particular release without affecting your master branch. That's where release branches come in. Release tags point to a single commit, which is great, but what happens if you need to make changes to that commit? Let's say you need to make a hotfix because you've found in your manual QA process that there's a bug in your production release? In that case, you're going to need to support a release branch that will allow you to make the additional commits to fix any bugs that you might find. So we can see here on the left that we have the master branch with a number of commits. It looks like we've pushed two of them to production and we've created release tags for those two commits, a version 1.0.0 and then a point release for a hotfix, version 1.0.1. On the right, we can see that we also have a master branch with a number of commits, but in this case, we've created two release branches, one for the 1.0 branch and one for the 1.1 branch, and in both cases, we will make changes and then create release tags for the various hotfixes we end up pushing to production. There are three key reasons why you would choose to create a release branch. The first is if you have a lot of manual QA. The second is if you have long running releases that you need to support and update over time. And the third is just to create them on demand when you need them when you have hotfixes. Let's look at each one of those three. If you have a manual QA process and you almost always have a number of hotfixes to every production release, it probably makes sense to start off by creating a release branch every time you choose to push to production. That way your QA team can work on the release branch, provide feedback to your developers, they can create a number of hotfixes, and then you don't need to tag and push to production until the release branch is ready to go. Here you can see a case where we have a release branch that we created and we made a couple of hotfixes on it before we finally decided to create a release tag for it. And then once we'd made those changes, we needed to get the hotfixes back into the master branch, so we merged them back into master after pushing to production. Another reason to create a release branch is if you have long running releases that you need to support over time. So, for example, if you've got customers paying you to support version one, version two, and version three of your code for a number of months or years, you're going to have to keep those release branches so every time you have security updates or other critical patches, you can patch each one of those release branches and then send them off to the appropriate customers. For many teams, if you don't need to support long running feature branches and you don't have an extensive manual QA process that often finds bugs in your code, you may not need to start with release branches at all. Instead, what you should do is start with release tags. And you can see here we have release tags, release one and 1.1. So what happened here was we started by just creating release tags, but then we released that we needed to make a hotfix to release 1.1. So we checked out the tag, we created a new branch called release branch 1.1, and then we made the hotfix on that branch so it didn't get confused with changes we were making on the master branch. Then what we did was we tagged that hotfix as a release 1.1.1 and pushed that to production, merged the changes back into master, and then deleted the release branch. So it's possible to just create your release branches on the fly, after the fact, if and when you need them, and that's often the best strategy for the majority of teams.
Releases in GitHub
In this section, we're going to look at releases, which are a GitHub-specific feature that allow you to add more information and functionality to your tags. There are two key benefits to releases. The first is that they allow you to share binaries with your users through GitHub without having to check the binaries into Git. The second benefit is that they provide you with the ability to put extended release notes in a way that's easy to share with anybody who's using your code or your project. There are two ways to create releases on GitHub. The first is to select an existing tag and to add binaries, notes, or additional information. The other option is to go into the releases tab and create a new release from scratch, and it will automatically add a tag as part of the process. One other benefit of releases is that they allow your users to be able to download a copy of your source code from a zip file without having to clone the repository. So within the release tabs, one of the things you can do is edit a tag, and when you click on that, it allows you to, in this case, we're selecting an existing tag and we're just adding an additional description to the tag. You can also just drag and drop binaries here to attach to them to the release, making it very easy for people to download executables or other compiled source. If you want to, you can also highlight if this release is a pre-release version and something people should be wary about when downloading or using. When you're done with making changes, you can click on the publish release button and it will save and publish your changes. The other way you can create a release on GitHub is to actually go and find a commit that you want to add a release to. As we look through our commit history, I see that there was a pull request for the kill list, and at the moment we don't have a tag for that, and it seems like that's probably a release we'd want to tag. So go to the releases tab and click on draft new release. We have no tag version, but if you go to the target and select recent commits, you can then scroll down to find the commit that you want to select. You can then give it the tag version. We'll call this 1.0.0. Add a release title describing the release, and then you can add longer release notes explaining the purpose of this particular commit. Again, if you want to, you can highlight that it was a pre-release and then you can publish this release. And now when we go back to the releases page, you will see that we can see both of these releases, one of which was created by a tag on the command line and then enhanced through GitHub, and the other of which was created in GitHub adding the tag after the fact.
Issues, Wikis, and GitHub Pages
(Song) She will clone and fork your repos Faster than you can blink And then tag, pushing for a quest while pouring a drink She started wiki's and pages to promote her skills But it's the branching and the merging what you Play on the bill Your only chance to find her is the user workflow Meet to release and you can access control You'd be pushing past security, then join her At the club Just to catch a glimpse of her mastering GitHub - You're watching Level Four of Mastering GitHub. In this level we're going to cover GitHub issues, the GitHub wiki functionality, and GitHub pages. Let's look first at GitHub issues. There are a couple of main reasons why you may choose to use the issues functionality that it's build into GitHub. The first common reason is that if you've got bugs you want to keep track of it often makes sense to keep track of those right in the repository with the code, with everything else. The other use case is it often makes sense to use GitHub issues to track stories or units of work that you need to deliver. And, in fact, some teams even put both of those into GibHub issues just choosing label to differentiate new features from barks. If you want to enable issues for a project it's really simple. Just go to settings, options and you notice that there are three check boxes. And the last one is the check box to allow you to enable or disable issues. By default it's enabled. Don't worry if you've got a bunch of issues and you uncheck the box and save it by accident. GitHub still keeps the issues, it just doesn't allow you to access them. So, just re-enable the check box and all of your issues, and all of their comments will still be there. If you're working on a project that's publicly accessible anybody can create new issues or comment on the issues. If you're creating a private repository just for the members of your team it will only be collaborators with access to the project that can view and create issues. Click on the issues tab in the right hand nav bar and you'll see a list of any issues that are being set up for a particular project. If you want to see what work is outstanding have a look at the list of open issues. If you'd like to get a sense of what the developers have delivered recently, look at the recently closed issues. When you look at the list of issues you'll see that you can see everyone's issues, issues that have been assigned for you to work on, issues that you created for other people to work on, and issues that have mentioned you either in the original issue or somewhere in the comments within at mention of your GitHub username. There's also the ability to filter issues by labels. One common patter is having labels for features and bugs so you can quickly see what functionality needs to be built and what issues you have with the functionality you've already delivered. You can even filter by multiple labels. Let's say you've found a bug in a project. You can create a new issue to notify the team that there's a problem. Just go to the issues page, then go in the top right hand corner click on the new issue pattern. When you do that you're going to get a form. The form first asks for a title for the issue to briefly describe what it's about. It also gives you a larger area where you can give a more comprehensive description and then if you know who should be working on it you can also select from a drop down list or type in any GitHub username to assign the issue to a particular person. There's also the option to assign the issue to a milestone if it needs to be done for your totodile release and you have the ability to add one or more labels to determine is this a feature or a bug and what functionality does it relate to. If an issue is assigned to you or if you get mentioned in an issue either in the body of the original issue or in any of the comments, you're going to start getting notified of any other changes that occur on that issue. Any other comments that are made, or any other commits that reference that issue. Sometimes that can be annoying if it's a long-running issue that you don't have any ongoing relationship with. So, if you use the button towards the bottom right hand corner, you can unsubscribe from an issue to make sure that you don't keep getting notified about what's going on. Equally, if there's an issue you haven't been mentioned in you can just click on the subscribe link on any issue and you will start getting notified anytime there's activity on that issue. You can also respond to an issue just by replying to any email notification you get about that issue. So, it's really easy to respond to issues even from a mobile device. Issues integrate really well with commits and pull requests. You can reference an issue in a commit and that would make the commit appear in the issue history and it would notify anyone who's subscribed to the issue. Also, if you use certain words like fixes or closes, or resolves and follow that by an issue number, a pound sign and the number of the issue if you put that in a commit message when that commit is merged in your default branch for most people the master branch that would close the issue automatically. Issues also support a wide range of keyboard commands for navigating quickly. So, especially if you're dealing with a lot of bug reports on a regular bases you can use the keyboard to speed up your work flow using GitHub issues. So, let's see this work in practice. We're going into this project and we're going to create a new issue. We click on the new issue button and we put in some kind of title to concisely describe the issue that we're having. We can select from a drop down list of developers which by default would be anybody who has been involved with the project to date. And we can either select from an existing milestone or if you wanted to, we could create a new milestone to assign this issue to. So, in this case, let's create a new milestone for the issue and then let's take a moment to put a little more of a description so whoever needs to work on this understands what we want them to do. And then, we submit the issue. Now, let's go into a terminal window and see how we can work with that issue. Let's open up the file, make the change that was requested and then we're going to add and commit those changes. But in the commit message we're going to make sure to say that it fixes number nine which is the issue number we just created. Then we can push those changes up to GitHub and go look at the issue and we see that it's automatically being closed 'cause it automatically identified that it was a commit on the default branch that mentioned the issue and because it used the word fixes, it knows that the issue should be closed automatically. Up to this point, we've just been looking at issues on a small project. But sometime is good to see how issues are used by large open source projects. Let's go look at rails and see how they use GitHub issues As we go to the rails project we can see that in the issues tab there's a list of outstanding issues. We can filter the issues by milestones so that we just see the issues for an upcoming milestone. Looks like the latest milestone had no issues but as we go to a milestone further in the future we can see there are a number of outstanding issues to resolve before that goes live. We can also filter by labels. Let's say that we just wanted to see the issues that related to activerecord. We can do that as well, so we can filter for example, by the issue within a particular milestone that relate to activerecord.
Welcome back. It's always a best practice to create a readme.md file in the root directory of your project. It allows you to tell people what the project's about why they should use it and how to install it and even how to contribute back to it. But as your project gets larger and more complex eventually the read me file is going to get a little too large to work with. When that happens you should consider setting up a GitHub wiki to provide more information about the project you've built. You may have noticed earlier, enabling wiki's for a project is done on the same page as enabling issues. You just go to settings, options, and under features make sure to check the box next to wiki's. There's an extra options for wiki's, which allows you to restrict editing on a public repository only to collaborators. So, if you don't want everyone changing the documentation for your project make sure to check that box. Let's say you want to add a wiki to your project. Start by clicking on the wiki tab on the right and you'll see that it gives you a welcome page to the wiki and asks you to click a button to create your initial page. When you click that button, it will give you a form by default it will set the title of the page to home but you can change that if you want and then it gives you a text area where you can enter the content for that initial page. Creating links is really easy. You just click on the link button and then insert the link text which can be any description you want under URL, which is either going to be the name of another page on a wiki or a full URL if it wants to be a link to something outside of your wiki. There are a numbers of buttons above the text area when you're entering content. You can use these to create headings, links, bolds, italics, and alike. But this isn't a Wysiwyg editor all that's going to do is generate markdown for you. So, instead use this if you can't remember the markdown but once you've used them a few times you'll probably just start typing the markdown straight into the text area. The markdown we worked with in readme files and in the wiki is GitHub Flavored Markdown. If you are new to markdown you'd obviously want to learn the basics of this. But even if you've been using markdown for a number of years in other projects, take the time to go to the URL at the bottom of this screen and learn more about GitHub Flavored Markdown because there are a number of specific differences compared to other flavors of markdown that exist. One thing you might want to add to your wiki is status badges. Here's an examples from the rails' Arel project where we're seeing badges to show that the build is currently passing in Travis CI and the dependencies are all up to date according to gemnasium. We're really just putting images in here. But those images get updated by those projects so it's a really easy way to dynamically show the state of your project in your wiki. This is a general feature of GitHub markdown and it can be used in wiki's or in readme files. In fact, the example we're using here comes from the Arel readme file rather than its wiki. So, let's look at the process of building a wiki. The first thing we do is click on the wiki tab and it's going to say welcome to your wiki. Create the first page. Click on the link and all you need to do is go into the content area and add some information. Once you've done with that, click on save page and notice the little metadata installed here about who made the change and when it was made. Now, let's add a new page 'cause the whole power of wiki's is linking across multiple pages. We can give it a title, enter a description, and when we're done, save the page. Then, let's go back to the home page and create a link to our new page. And to do that, all we need to do is type the text before the link, click on the link button, and enter the description we want for the link and the page it should link to. And notice, we can just go in and change that description for example, it's just a text file. Now, when we go to the home page, after saving that page we can click on that link and see that it takes us to our new rules page. You'll also notice that all of the pages we add are added to a navigation box on the right of the wiki page.
Have you ever wanted to host a simple static website relating to a project or an organization you're involved with? GitHub pages can allow you to do that adding it to an existing repo or an organizational account. There are two main use cases for GitHub pages. The fist is to add richer documentation and information to a specific project. The other is to create a page either for a user on GitHub or for an organization. Let's say you wanted to create a webpage just for yourself. Well, the first thing you'd want to do, to do that using GitHub pages, is create a repo for your username.github.io. It's important you'd follow that convention when naming it. Then, you can go into the settings, scroll down to the GitHub pages area, use the auto page generator, write your content, pick a theme and publish. Let's look at how that works step by step. In this case, we want to create a page for deadlyvipers. So, it's an organization rather than a user but it's exactly the same process either way. You start by clicking on the link to add a new repository and you name the repository as user or organization name dot github.io. When you do that it'll create a standard page and you'd usually expect to have to push content up. We're going to do something different. Just click on settings, scroll down the page to the GitHub pages section and click on the automatic page generator. That would then give you the very first page and you can start by putting some content in as a title and by updating the description to describe what you want about your organization or your user account. Click the button at the bottom to save the content and then you get to select a theme. Don't worry you can create custom, html, and css. This is just to give you a starting point so you can make something that looks fairly attractive, quickly. Once you've selected a theme, click on the publish button and it would take you to a page, showing all of the html, css, and other content that was generated. And then the top of the page tells you the URL you need to go to, to view this page. If you go to that page immediately you'll probably not see anything at all. But if you give it about 10 minutes, you would then see that the site is being pushed live to that URL. Any general changes take about 10 minutes to get pushed up. If you want to create GitHub pages for a project this is often something you do, you started with a readme file, you upgraded to a wiki but eventually you want not just room for more content but also a more attractive looking feel. If you wanted to do this, is basically the same process that you do if you were creating a new site for a username or an organization. The difference is that you're not going to create a new project, it's going to create a new branch within an existing project. So, you just go into settings, select the GitHub pages, automatic page generator, write the content, select a layout, publish it, and the content you created will now be your gh-pages branch. Let's go through this process. So, we've got an existing repository, we click on settings, scroll down to GitHub pages and click on the automatic page generator. It then gives us a form for entering our initial content. We change the title, replace the description with the content we want to share and save the page. We then pick a theme and once we've done with that we click on the publish button. For a user or organization page the URL is going to be the user or organization name.github.io. For a project page, though, the default URL is going to be user name.github.io slash repository name. So, for example, in this case is deadlyvipers.github.io/dojo_rules. If you want to be able to access your GitHub pages content at a custom domain name you can set that up really easily. You just create a file called CNAME that is in the root of your repository. And of course it's going to be on the same branch as your GitHub pages content. And then what you need to do is configure that CNAME with your DNS host. So, let's look at the process. Here, we're going to create a custom URL to get to the deadlyvipers home page. Firstly, we go to the page's repo that we've created. So, we're working here in the master branch. Then, we want to add a file called CNAME. We could clone the repository, download it and make changes locally but let's just make the change by clicking to add a new file right through GitHub. We'll name that file CNAME. What we need to put in this file is the domain name that we want to point to this GitHub pages site. We need to put a commit message in and save this change. Next, we need to go to our DNS provider to add a new record and all we need to do is find the domain name, look at the host records and add a new CNAME for whatever subdomain we want in this case pages.deadlyviper.com. And point that to the user name.github.io. So, in this case deadlyvipers.github.io. Let's see what that's done. Well, if you go to the original URL you see that the content is here but if we go straight to pages.deadlyvipers.com you see there's nothing here. And, in fact, you'll have to wait usually 10 or 15 minutes for the DNS to propagate, to get to the point where you can see the content at pages.deadlyviper.com.
Managing and Securing GitHub
Configuring a New Repository
(Song) She'll clone and fork your repos Faster than you can blink And then tag, push And poll request while pouring a drink She studied Wikis and pages To promote her skills But it's the branching And the merging which'll pay all the bills Your only chance to find her Is to use a workflow Commit to a release And you can access control You'll be pushing past security To join her at the club Just to catch a glimpse of her Mastering GitHub - There are a number of options available when you configure a new repository. Most of them you'll be familiar with but there might be one or two that you've not encountered before. Once you've created a repository, go into settings and click on the options tab. There are a couple of interesting settings under the options tab. One of the first is the ability to change the name of your repository. And the best part is, if you rename your repo, any existing links to it will still work, they'll just get forwarded right along. Another interesting option is the ability to change the default branch from master. Most of the time you wouldn't do this, but let's say that you had a whole bunch of users very comfortable with subversion. If you wanted to, you could create a new branch called trunk and make that the default branch. Why does a default branch matter? Well, it's used for a number of things. One example would be when you close an issue using a commit. The issue won't be closed until that commit is merged into the default branch. So, it's important to think what default branch you want and configure that correctly. Of course, you can also configure Wikis and issues, switching them on and off as we saw in earlier sections. And you can configure GitHub pages to use the automatic page generator to create your GH pages branch with some content for showcasing your project. There are a few options you need to be careful about. You can take a repository and change it's status from public to private or vice versa. You can transfer the ownership to any other user or an organization that you're responsible for, or you can delete the repository. Under the collaborators tab you can add new people based on their GitHub username to collaborate with you on a project. If it's a private repository you need to do this for them to be able to see it at all. If it's a public repo, you're giving them full read and write access, but you're not giving them administrative access. So, for example, they can't change settings for the site or add new collaborators themselves. There are also settings for managing webhooks and services and deploy keys, but we'll be looking at those a little later in this course. Let's quickly go through the process of configuring a new repository. In this case we're going to add a new repository to this organization to deadlyvipors. We're going to give it a name, make sure it's unique and optionally give it a short description. And in this case we're going to initialize it with a ReadMe file so we don't need to create files locally and push them up to the server. We do that and now we have a new repository with a ReadMe file. Now, let's go into settings and in this case we want to limit it so that only collaborators can add and change content on the Wiki. And let's rename the project as well. Now let's talk a little bit about managing a project using GitHub. Let's say you were getting started with the Rails project. Well, the first thing you want to do with any new project is look at the ReadMe file. It should give you information on the goals of the project and how to download and get it configured so you can get it running locally and start to run the tests. Next you might want to see what people have been doing on the project recently, and a good way to do that is on the right hand side of the screen there's a pulse tab. If you click on that, it's going to show you an overview of the recent activity. What's been going on in the last few days, weeks, or months. Let's look at the information on this page one piece at a time. Firstly, you can look at an overview of pull requests, showing the number of merged pull requests, how many features have been completed over the period time. And then secondly looking at the proposed pull requests, how many new features have been added to the project in the last week or month. You can also see some statistics around issues to see how many issues were closed and how many new issues were added. Most of the time, hopefully the first number will be bigger than the second. You can also get an overview of who's been doing what to see the number of authors, how many commits they've made, and how many additions and deletions there have been to the code base in terms of lines of code. As we scroll down the pulse page, it shows us a listing of the pull requests that were merged and proposed. This is a great way to just get a sense as to what people are working on and talking about. As we go further down the page, you'll see that there's an issue listing as well. So, you can see the specific issues that are being closed and opened recently. This is a great way to get a sense of what kind of functionality you're having trouble with and what kinds of things you're successfully clearing out. Another important part of the pulse page gives you the conversations listings. Now, these are conversations that occurred on old issues or pull requests that aren't closed yet. It's a good way to pick up other bits and pieces of activity that might not have been reflected under issues or pull requests. An important thing to realize about pulse is that it's showing deltas, it's showing you how many pull requests were merged, or proposed, or how many issues were opened and closed, but what it's not showing you is the total number of pull requests that are outstanding, or the total number of issues that are still live. So, pulse is a good tool for getting a sense of the directionality of the project but the next thing you're going to want to do is look at some absolute information. For high level information it's also worth checking out the graph section. There are four graphs here for contributors, commit activity, code frequency, and a punch card. Let's look at what each one does. The contributors graph allows you to find your most valuable developers. It allows you to see who's been doing the most work over a period of time. By default it will show you the number of commits, but if you want, you can see the most active people based upon the number of additions or deletions to the code base. And you have the ability to easily select a period of time. You just drag your mouse over part of the graph and you'll be able to see who the key commiters were in that period of time. The commits graph shows the busiest days and the busiest weeks. At the top it shows you a series of weeks, so you can see how activity has changed over time. And at the bottom it shows you the number of commits per day of the week, so it looks like Wednesdays are a great day to code on the Rails project. The code frequency graph is particularly interesting because what it allows you to do is see the number of additions and deletions over a period of time. So, for example, we can see that there was a point towards the middle of this graph where there was a lot of refactoring going on in the code base. Even though the number of commits might not have been that much greater than steady state. And finally, the punch card graph allows you to get a sense what times of day and days of the week are getting the most commits. It's a function of the number of commits made over the project's life during any given hour of any day. The punch card graph gives you an idea of the most productive times of the day and days of the week. Each punch is a function of the percentage of the project's commits over its lifetime that've been made on a particular hour in a particular day. So, it just gives you a quick, easy view of what days and hours people have been committing most frequently. Next, you probably want to look at the absolute state of the issues. How many issues are there outstanding and what are they about? And as we saw earlier in the course you can filter these based upon whether they relate to you or particular labels or milestones. And you're also going to want to look at the absolute state of pull requests to see how many outstanding pull requests are there and what are people working on. This is the best screen for seeing work in progress for the team. Finally, it might be worth looking at the absolute state of branches too. It will show you how many different branches you have in the repository, irrespective of whether or not they connected to a pull request. Most of the time, there'll be a correlation between branches and pull requests. But if somebody's doing a pull request from a remote fork, there won't be a branch and if somebody's been doing some work and has shared it on GitHub, but has not yet started the conversation, the pull request, you may have a branch without a pull request.
In this section we're going to look at some of the authentication and authorization options in GitHub. It's important to realize that other than signed tags, Git doesn't have a native concept of authentication at all. You'll have to identify yourself as an author based upon your name and email, but you can put any strings into those fields that you want. GitHub doesn't do much about authentication either. For example, what GitHub does is it identifies commiters based on their email address. So, let's say you wanted to get David Heinemeier Hanson to commit to your repo, it's easy, all you need to do is configure your global user email to email@example.com. Make a change, add it, commit it, push it to your repo, and as you see on your screen here, you too can get David to contribute to your open source project. GitHub follows the Git philosophy of trusting your team and because of that there's fairly limited access control functionality built into GitHub. Deliberately. Owners on a repository can do anything they want and if you add somebody as a collaborator they have full read and write access to the repo. They can make any changes they want to any branches and there's nothing you can do to stop them. There are however easy things you can do to undo any changes that they chose to make. If you've really got people working with your project that you don't want to provide full read and write access to, just ask them to create a fork. Forks are effectively the main unit of access control on GitHub. Another common pattern is to have all of you developers working on the same code base but then have a separate repo that you send pull requests to that only your operations manager or team lead can accept. Even though permissions in GitHub are very course grained, you either have access to a repo or you don't, with Git you often have a large number or repositories. And if you also have a large number of developers, it can be hard to manage that mapping. As you hire a new developer, making sure that they have access to the 30 repos they should can be a chore to maintain. So, what you'll often do is use organizations to own code, either for a company or for an open source project, and then use teams to provide easier management of permissions because you can add a developer to a team and then give team access to the 30 repos it requires. It used to be that SSH was the preferred way of connecting to GitHub, now both HTTPS and SSH work just fine but generally HTTPS is preferred. The only thing you're going to want to do is make sure to use a credential helper so you don't have to keep typing your password every time you connect. The other thing that's worth doing is upgrading to two factor authentication. So, every once in a while you will get a text message from GitHub giving you an access code to make sure that if someone else gets your password, they can't access and change all of your repos. Access tokens can be used instead of passwords for working with Git over HTTPS. They can also be used to authenticate to the GitHub API over basic authentication. There's a number of reasons why you would choose to use access tokens. Firstly, if you've configured two factor authentication, your password won't be enough to connect over HTTPS and it won't ask you for the second factor. So, you'll need to create a personal access token to be able to connect to GitHub over HTTPS. And make sure to enable password caching so you don't need to remember the contents of that password token. The second reason you might want to create an access token is if you have an application that you want to provide access to your GitHub repos. Either by pulling and pushing using Git or via the GitHub API. If that's your use case, you should create an access token for that application. You should treat those access tokens the same way as you would passwords and make sure never to commit them to your code base. To create an access token just go to edit profile, applications, and click on generate new token in the personal access tokens section. Give the token a name that will make it clear why you created it, command line interface for my mac, or access for the widget generator. And you can limit the scope for those tokens. By default they have repo, public repo, user, and gist scopes. So, that allows you to access private and public repos, update user information, and create gists. There are a number of other scopes available though depending upon what you want to do, so take the time to learn and see what the scopes are and which ones are necessary for the application you're building. There are a number of different strategies for connecting deployment scripts and automated scripts to your GitHub repo. There are four common approaches to providing deployment scripts with access to your GitHub repo. You can use SSH agent forwarding OAuth access tokens, deploy keys, or machine users. With SSH agent forwarding, you log in to the machine that is running the script and you can configure forwarding so it will use your SSH credentials. That's fine, but it doesn't work if you want the script to run when you're not there. OAuth access tokens can be a good next step, they allow you to create a personal access token and provide that to the script. This allows the script to have the same access you do. So, the good news is it's very easy to configure, the bad news is it'll have access to all of your Git repos, not just the one you're working with. The next step is to create a deploy key. This allows you to create something like a personal access token but just for a single repository. Reducing your security footprint. And then the final option is, let's say that you've got a script that needs access to 20 Git repos, but you've got access to 60 Git repos and you don't want to share that, you can just create a new username on GitHub just for that script and give it access to only the repositories that it needs. Under edit profile security, it's also worth looking at the sessions section. It will show you the different devices that've connected to GitHub as you and the last times they connected. As you scroll down the page, you can also see a security history of the important things you've done on GitHub. And it's worth logging in here every once in a while to make sure that somebody else hasn't been making changes to your account.
Integrating Existing Services
Welcome back. In this level, we're going to look at various ways of enhancing your GitHub experience. Everything from integrating third party applications to working directly with a GitHub API. There are a range of pre-built services available for easily integrating well-known applications like Basecamp, CircleCI, or Asana into your repository. There's a list of all the supported services along with documentation explaining what the integration is and how to use it in the GitHub services repo in the Docs directory. If you want to add an existing service to your GitHub repo, just go into the Settings tab for your repository, click on the Webhooks & Services option, and then select the service from the drop-down list. So let's go through the process of adding a third party service to a GitHub repo. Start by clicking on settings, then click on the Webhooks & Services tab. And then after clicking Add service, you can star to type the name of the service you want to integrate. In this case, we're going to use Code Climate as an example. It may ask you for your password. And then once you've entered that, you just need to follow the install notes that is specific to the application you're working with. And once you've done that, click on Add service, and you'll see the service listed under your services. And it's easy to add multiple services. Let's take a moment here and add Basecamp. And you'd enter the information it asks for, Add service, and it'll add it to your list. It's equally easy to remove services just by clicking delete next to the service you no longer want to integrate with this repository. Most of the popular projects you work with should already have a service created for integrating with GitHub. Each one has different behaviors. For example, if you use the Basecamp for agiles and integration, it'll just add a list of your commits to the progress page. That's all it currently does. Of course if use something like JIRA integration, you can actually resolve issues in the same way as you do in GitHub issues just by adding the appropriate text to your commit messages and merging them into your default branch. Another common type of integration is with a continuous integration tool. Jenkins, Travis CI, CircleCI, something like that. And those will allow your test to automatically be run every time you make commits to the repository. With CircleCI, you just sign up with CircleCI with your GitHub credentials, and you don't even need to configure the settings in GitHub. It will automatically run your test every time you push changes to your GitHub repository. We've seen how we can integrate existing services with GitHub, but it's also possible to use custom webhooks to integrate your own applications with your GitHub repository. In GitHub, you can create webhooks. These are http calls that will notify your application every time a specific event happens within a repository. These hooks can be used for anything from updating an external issue tracker to triggering continuous integration builds or deploying to a production server. It's basically a post request that will get sent to a URL that you provide to GitHub in the next screen. When you add a webhook, you need to start by entering the payload URL. This is the URL that you want GitHub to call every time a notification is fired. You can select the content type. Usually, you'll use application/json. And if you want, you can provide a secret so you know that the call is coming from GitHub. Then finally, you can decide what should your application be notified about. It can just be notified about push events, when somebody pushes changes to GitHub. It can be notified of every kind of event that occurs relating to your repo, or you can select the individual events that you want your application to be notified about.
The GitHub API
Welcome back. If you want to integrate your customer application with GitHub, sometimes a webhook is all you need. If you want to get notified every time somebody pushes new commits to GitHub, a webhook will do that fine. But what happens if you wanted to see the history of all of the commits in a repository, or list of all the users who've committed to that repository? In that case, you'd need to do something different, and that's where the GitHub API comes in. You'll probably end up working with the GitHub API using a programming language of your choice, but let's use curl and the command line to see some of the kinds of commands that the API supports. Let's start with the simplest possible request. Let's just use curl to call api.github.com. And as you see, that returns a discoverable list of all of the API calls that are available. You can even do things like see a full list of the emoji supported by GitHub by curling https://api,github.com/emojis. Let's try to get a little publicly accessible information about a particular user. We just curl API.github.com/users/username. And now let's run it with a -i flag so that we can see all of the header information, as well as just the response. And you want to notice in particular here the rate limit and rate limit remaining headers, which show you how many more request that you can make typically within the next hour. We can also do things like getting a list of the publicly accessible repositories for a user by using curl api.github.com/users/username/repos. If you want to do anything more interesting than this, we'll probably need to authenticate. The best way to do that is to create a personalized access token, and to use that for testing the API. The easiest way to do that is through the website. And then you can take that token and use that to make authentication calls. So let's say I wanted to get more information about my user account. I could run the following command. I'm going to curl -i to get the headers, -H. And in the header, I'm going to add my authentication token. And I'm going to call API.github.com/user to get my user information. And it will return all the information that's available about me as a user. If I want to create a repository, I can do another curl command where I passed the authorization token. And with -d put the name for the repository and go to api.github.com/user/repos. So I'm posting information here to add a new repository. How about adding an issue to that repo? Well, if I just type a slightly different command in, now I'm going to create a title, a body, and let's say a label of critical, and I'm going to send this payload to api.github.com/repos / my user name / the repo name /issues. And by doing that, as you can see, it create a new issue. And if we go to the website, we see that that issue has been created successfully. The API supports providing information on activity. It allows you to create gists, it provides access to read and write raw get objects so you can really get into the GitDB, and it allows you to implement any Git functionality via the API. It also supports working with issues, organizations, pull requests, repos, search, and users, as well as some miscellaneous bits and pieces like listing the emojis or gitignore templates or things like that.
Command Line GitHub
Getting Started with Hub
(Song) She will clone and fork your repos Faster than you can blink And that tag push and pull requests While pouring a drink She studied wiki's and pages To promote her skills But its the branching and the merging Which will pay all the bills Your only chance to find her Is the user workflow Mid to her release and you can access control You'll be pushing past security To join her at the club Just to catch a glimpse of her Mastering GitHub - Welcome back. In this level, we're going to look at hub which is a command line tool that allows you to access a lot of the functionality of GitHub without having to use a browser. GitHub's great, but it's a website, and so because of that, every time you want to do something, you're testing your hand eye coordination by using a mouse to click through. Whether you're working with issues or pull requests, wouldn't it be great if there was a way that you could create those and work with them from the command line? Well, that's exactly what hub allows you to do, and it also gives you a number of superpowers to get so that you can more easily clone, fork and work with various GitHub based repositories. So the first thing you'll need to do is get hub installed. On a Mac, the easiest way to do it is to use the Homebrew package manager and just brew update to make sure it has the latest recipes and then brew install hub. If you're on another operating system, you're going to want to clone the GitHub hub repository, cd into that and then you're going to have to rake install, so you're going to have to make sure that you have Ruby installed on your machine to make this work. There are two ways of using hub. The first way is you can use the hub commands directly so if you want to use the clone or fork functionality, you'd type hub clone or hub fork. The second option is to alias hub as git. You can literally just type alias hub=git or more likely you're going to want to add this to your terminal profile. Then you can run commands like git clone or git fork and it's going to start by using the hub functionality and then just degrade naturally to using git functionality if you don't need hub. There's a couple of important points to bear in mind when working with hub. The first is if you're in Windows, and you're using msysGit, which is what I'd recommend, you do not want to alias hub as git. It will slow down your command prompt way too much. The second is if you use bash or oh-my-zshell, you're going to want to implement tab completion, and I've added a couple of links to the slide here that you can use to download those scripts. So let's try the basics here. Let's say we wanted to create a repo using hub. How would we do that? Well, we would git init as we usually would to create a local repository on our laptops. Then create some content and add and commit that to the local git repository, but now here's where things change. Instead of having to go to a browser, go to GitHub and add a new repo, you can just type git create to create a new repository for this project on GitHub. Then just git push -u to set the default upstream, origin master, and you can even use git browse to open up a browser and see this repository in GitHub. So let's say we wanted to create a pull request using hub. Well we'd git checkout -b to create a new branch locally, create some new code, add and commit that, and then git push -u origin new_branch name to push the new branch up to GitHub. We need to have a branch before we can create a pull request, but then again, instead of having to go to the browser, all we need to do is type git pull-request. It will throw us into our default text editor and allow us to create a title and description for that pull request and it will generate it for us automatically. Even cloning is easier with hub. Instead of having to type git clone https:// github.com/username/project, we can just git clone repo_name if it's our repository. If it's a repository owned by somebody else, we just git clone username or organization name /repo and that will clone the repository automatically. Forking a repo is also much easier using hub. We would start by cloning the repository so that we have a copy of the repo locally so let's take the deadlyvipers/dojo_rules and clone that. Then, you cd into the directory and just run git fork and that will create your own fork of this project on GitHub. Now the only problem is if you want to use things like git pull request, at the moment, origin is still set to the deadly vipers fork, so what you have to do is go in and edit your docket/config file to change origin and the fork of the repo, to change those names around, and let's see all of this in a screen cast. Let's start by creating a new repository. We'll initialize it, create some content, add and commit that locally, and now we can use hub to create a repository on GitHub, and then we can push out changes up to that repo. Now let's create a new branch, add some code to it, and push that branch remotely as well, setting a default upstream. Now we can use hub here to git or hub pull-request to create a pull request. We enter the title and description and now if we run hub browse, we can go to the repo and see that under pull requests, there is a new pull request that's been added and associated to the branch we just created. We can also easily clone a repo just by entering either the name of the repo, if it's one of ours, or the username or organization name and the name of the repo if it's somebody else's project. Let's say we want to fork that project. Well, if we do that, then pull-request isn't going to work because the remotes are going to be wrong. So the easiest way to fix this is just to rename the remotes in the docket/config. We could create a branch. Let's add some content and commit that, and now we can push the branch successfully and we can use git pull-request to create a pull request, enter a title and description and git browse to see that on our fork of the repository. So hub allows you to do a lot more than just cloning, forking and creating pull requests more quickly. Let's have a look at some of the other ways that you can use hub to more effectively collaborate with your team. Let's say that you're using a fork-based collaboration model and you've got a new collaborator on your team that you want to pull some changes from. Well now all you need to do is git remote add username or even just git fetch username and it will add them as a remote and fetch their changes so you can see what they've been working on. Let's say that there's a fork of a repository that you're working on that has a commit you need but you're not collaborating with that fork on a regular basis. No problems. Now you can use git cherry-pick to cherry-pick any SHA-1 hash for a commit from any fork of a project you're working on. All you do is type git cherry-pick username@SHA-1 hash and it will pull down that commit from that fork and apply it to your local branch. Another common problem is when you want to check out a pull request but it's a fork that you've not worked with before. You don't have it set up as a remote. With hub, that's no problem at all. You just git checkout the URL of the pull request and then the name of the custom branch you'd like to create locally and it will go find the fork, find the branch and create that as a custom branch for you locally that you can then run the tests and see how it works. Let's say that somebody has created a pull request and you want to merge it in, but again, you don't have their fork set up as a remote. No problem at all. With hub, all you need to do is type git merge and give the URL of the pull request and it will automatically handle the process of finding the appropriate branch on the necessary fork and merging it in. Once you've done the merge, you've then got two options. If you like what you see, you can push the merge back up to GitHub. If it was just for test integration, maybe you were just trying to test what it would be like to integrate somebody else's feature branch with your own, you can just git reset --hard HEAD~1 to throw away the merge and continue with your work. So let's try a couple of scenarios right here on the command line. Let's first start by using git fetch username to pull from a fork and if you want somebody else on our team's been working on. We could even cherry-pick. How about we look at a fork that we don't have a copy of locally and that we don't have set up as a remote, and let's find a commit on it that we'd like to work with. So now we can just git cherry-pick with the username and the SHA-1 hash for that commit and it will pull that down and add it to our branch. And let's say we want to merge a pull request from somebody else's fork. We can just git merge and then provide the URL for the pull request and it will merge it, creating a merge commit on our local master branch, and then if we are happy with that and the tests run well, we can push those changes back up to GitHub to close the pull request.