If you looked at git-intro, then you should have a basic understanding of how to create a repository, add files, commit changes, and go back to old commits.
What more could there be?
Oh boy, tons! But in this section, we're going to talk about the following topics:
- Remote Repositories
Cool! So get ready, this is where we get to do the fun stuff with git :)
In git-intro, you worked entirely on a local repository, which means the repository was on your computer and nobody else's. However, you can imagine that this may not be the best idea. For one, if your computer breaks, then you lost all of your work. Second, we said that git was a tool that aided collaboration, and if the repository is only on your computer, how are others suppsed to get your work?
That's where a remote repository comes in. Remote repositories are copies of your repository that are located on some other computer. You can then push commits to that repository or pull commits down from that repository. Git doesn't have any built-in thing that makes a remote repository special - it's literally just a copy that you can update when you feel like it. However, by convention, we often have one remote repository that we treat as the master copy. Collaborators will add their commits to it, and we can pull new commits down from it.
There's two scenarios when starting work on a remote repository:
- Someone else already has a repository made, and you want to make a 'clone' of it so you can start working on it.
- You have a local repository, and you want to put it on some remote server to act as a backup or to let other people work on it.
Let's start with scenario #1!
Cloning a repository
When we make a copy of a repo in git, we call it 'cloning'. To clone, you simply type the command:
git clone <url of repo>
At that point, git will pull down all of the code and put it in a folder whose name matches that of the repository. As an example, let's clone this repository! Simply type:
git clone https://github.com/luacm/git-intermediate.git
And ta-da! You now have a local copy of this repository.
Adding a remote repository
If you're working on a project, I encourage you to use the above method, just because it makes things easier. You can make an empty git repository online (like on Github or Bitbucket) and clone it to start istead of using
git init. It's also easy to add a remote to your existing repository, it's just a couple more steps. So, let's begin!
Assuming you have a local repo already, let's make a repository on Github. Just go to the site, login, and click the 'Create a new repo' button that's next to your name in the top left (or just click here). From there, just enter the details about your repo like the name and such. I always initialize with a Readme if I don't have one yet in my local repository, just because every project on Github should have one. You don't have to add a license, but if you do, the MIT License is a good one that lets people dow whatever they want with your code as long as they give attribution.
Now that you have the repo created, look for the 'clone URL' located somewhere on the page. Right now it's in the bottom right, but it's changed location over time. It may default to the 'SSH clone URL', but we don't want that one. Click on the HTTPS button to see the 'HTTPS clone URL'. Copy that URL.
Now let's go to our local repository and type the following command:
git remote add origin <the url you copied>
You now have added a remote repository called 'origin'! By convention we call the primary remote repo 'origin' because that's normally where you originally get your code from. You can pull down the differences between your repos (for instance, if you added a Readme) by typing
git pull origin master or just overwrite the existing remote repository with a copy of yours by typing
git push -f origin master.
But we haven't really gone over those commands, have we? Let's do that now!
Pulling and Pushing
We need a way to communicate with the remote repository and share commits. That's where
push come in.
When you do a pull, you get all of the new commits from the remote repo you specify added to your local repository. And that's it! There isn't much to pulling code at all. As an example, to pull from your origin remote by doing the following:
git pull origin master
And then you'll get your code! Don't worry if you don't know what the 'master' part means. We'll be going over it very shortly.
Pushing is how you take the commits from your local repo and add them to your remote repo. To do that, all you have to do is type:
git push origin master
And it will add your commits to the remote repo. Simple, right?
Now to explain what that 'master' word we've been writing means by looking at one of the most useful tools git provides you: branching.
Imagine the following scenario: You're writing a paper for class, and you're about halfway done. That's when you realize that you think you need to adjust your thesis, but doing so would require re-writing a few paragraphs. You don't want to lose your current version, so you make a copy of your paper and work on the copy instead, so you have a backup if anything goes wrong. That's branching in a nutshell. It's the concept of working on a copy (called a 'branch') so you can change things without worrying about ruining your current version. It's one of the greatest features in git, and it's really simple to do.
Let's make a branch!
First, let's all start off with the same repository so we can walk through this together. How about the Programming Club website? Yes, it's on Github, and you can totally help work on it. So let's clone that one.
git clone https://github.com/luacm/luacm.git
You now have a copy of the website! It takes some setup to get it running on your machine, but if you're curious, you can follow the instructions in the Readme to get setup. But alas, this isn't the web development workshop!
ls and a
git status to get your bearings. You'll see there's a bunch of files there. What the files do isn't important. But let's imagine that you wanted to add something to the website. You could change the files right here and commit your changes, but what if you screwed something up? Sure, you could use
git reset --hard to go back to the old version, but doing a reset is a pretty dirty solution you don't want to use too often. It messes with the history and can be easy to make mistakes with.
Instead, this is a perfect time to branch. Type
git branch now. It'll show you a list of branches, which will include things like
master and maybe some others (at the time of writing, there is also a
news branch). Each branch represents a different working copy of the project. There will be an asterisk next to
master, indicating that is the branch you're currently on. So let's make a new one!
git branch kingpin. This will create a branch called 'kingpin'. However, if you type
git branch, you'll see you're still on master. To switch to kingpin, type
git checkout kingpin. Now when you type
git branch, you'll see you're on kingpin.
Let's do some stuff on our new branch!
Ah, a new branch! Freedom! You can do whatever you want here (add files, delete files, make commits) and it won't affect our master branch at all! This is the beauty of branches. Let's do some stuff to it.
- Open up LICENSE in your text editor of choice and change the content to
This project is the property of Wilson Fisk.
- Stage the change with
git add LICENSE
- Commit the change with
git commit -m "Transferred ownership."
So now we have a new commit on the kingpin branch. But what if we decided that we shouldn't have handed the project over to Marvel's most feared mob boss? Good thing we did this on another branch! Simply type
git checkout master. Now if you type
git branch, you'll see that we're on the master branch. And if you open up the LICENSE file, you'll see we got our old license back! And, if you type
git log, you'll see that our new commit we made transferring the ownership isn't in there at all!
To show that this works both ways, you can type
git checkout kingpin and open the file again, and see that it belongs to him in that branch. Hopefully you can see how by branching, we've created two copies of the project that we can easily switch between. This is a very powerful feature in git. But what if I don't want a branch? What if I decided I liked giving the project to Kingpin, and I want that to be back on my master branch? Well, that brings us too...
Merging let's us take two branches and smash them together. Typically, this involves merging a branch back into master. This brings us into the core workflow of git, which involves having a stable master branch and creating what are commonly referred to as 'feature branches' to work on new stuff. When that stuff works, we merge back into master.The important thing is that the master branch is always functioning.
So let's merge that kingping branch in. First, make sure you're on the master branch with
git checkout master. Now, simply enter the command
git merge kingpin. You'll get what's known as a 'fast-forward merge', and you notice that if you look at the LICENSE file or the
git log, you have successfully merged the two branches together!
But alas, you can imaging that merges don't always go well. Imagine the following series of actions:
- You make a branch off of master called 'feature'
- You make some changes and commit them on 'feature'.
- You checkout master, make some changes and commit them.
- You try to merge.
There's two thing that could happen here.
- If the commits on the different branches changed different files (or different parts of different files), the git will perform what is called a recursive merge. It will put all of the files together and make a new commit for the merge. Yay, git!
- If the commits on the different branches changed the same parts of the same files, then git will have no idea what to do. It's actually impossible for it to know what to do, since both parts have changed since the branch. This is called a 'merge conflict'. To fix a conflict, you open the conflicted files, edit them to be how you want them, save them, and then commit the changes. And then you're done!
Workflow to avoid merge conflicts
You can imagine that merge conflicts are undesireable. However, we can follow certain practices to make sure they never happen or rarely happen. For example, if you're working by yourself, avoiding conflicts is easy: just never edit both branches simultaneously. It's really rare that you'd ever do that if you're working by yourself, so merge conflicts here should be a non-issue.
Working in groups poses some bigger problems. People are going to be merging in their features into the master branch as they finish them. You can alleviate some of the merge stress by always merging master into your feature branch everytime someone changes something. This means at worst you get a few, easy-to-solve merge conflicts. It'll definitely make it easier to merge your branch into master later.
Also, how you structure your features will help a lot too. Each feature should be compact and affect only a few files. If your feature affects all of the files in the project, then you're going to have merge conflicts no matter what. But if you keep your changes specific and precise, then merge conflicts will be a rarity.
Congratulations! You now know enough to work collaboratively with someone on a group project or at a hackathon! In the next workshop, we'll go over advanced git techniques and how to work on really big projects will lots of peolple.
git clone <url>: Makes a clone of the repository at the given url.
git pull <remote name> <branch name>: Pulls in the new commits from the specified branch on the specified remote repository.
git push <remote name> <branch name>: Pushes your new commits from the specified branch to that same branch on the remote repository.
git branch: Lists your branches, putting an asterisk(*) by the active one.
git branch <branch name>: Creates a branch with the given name, but does not switch to it.
git checkout <branch name>: Switches to the specified branch.
git checkout -b <branch name>: Creates a branch with the given name, then switches to it.
git merge <branch name>: Merges the specified branch into your current branch.
- LearnGitBranching: A fantastic game where you learn git commands, especially branching, as you play.