Skip to content

AO3 Coding: More About Git

redsummernight edited this page Jul 2, 2021 · 4 revisions

Note: This is the third part of a four-part tutorial aimed at AD&T Coding Volunteers. Not all of the information will apply to contributors who are not official volunteers, and it may include links to internal documentation and references to tools (e.g. Slack) that are only accessible to official volunteers.

Please do not edit this page unless you are an official volunteer. Instead, contact AD&T using the email address on the bottom of this page to suggest changes.

This page will guide you through some of the more advanced -- but still common -- things you can do with Git. It's good to read and understand as much as you can, but don't worry if it doesn't all sink in yet -- it's easier to learn by doing.

Table of Contents

Introduction

This tutorial assumes you've set up your development environment, know how to modify files using either a GUI or command line text editor, and are familiar with the basic Git commands you used to create your first pull request in AO3 Coding: Your First Pull Request.

NOTE: $ indicates things to type at the command prompt. Do not include the $!

A note for Subversion users

If you are used to working with Subversion instead of Git for version control, you might want to read this crash course in Git for Subversion users before coming back here.

You will be committing a lot more in Git than in Subversion. One important distinction between SVN and Git is that when you make commits to Git (git commit) they are local to the repository you're working in until you decide to git push them somewhere else. This means that no one else will be able to see your changes while you're working. All the commits stay on your copy of the repository until you're ready to share them with the world.

The same is true for branches. You probably didn't work with branches in SVN much, because SVN branches are heavy and difficult to work with. Git branches are very lightweight and very useful. We'll use branches quite a bit in Git to organize changes to the code.

The last big difference between Subversion and Git is how Git thinks about changes. Subversion is concerned with tracking files; Git is concerned with tracking changes. The distinction is subtle at first, but it will become clearer as you begin to work with Git.

Branching

Branching is an integral tool when using Git. Branches make organizing code much simpler and while we can work on our master branch, that doesn't mean we should -- and we should never, ever commit to master. It's a much better practice to work on branches. We can use git checkout to create and move to a new branch named after the JIRA issue we're working on:

  $ git checkout -b AO3-1234

This is a shortcut for git branch new_branch followed by git checkout new_branch. You can use git status to see what branch you're on:

  $ git status
  # On branch AO3-1234

For now, just make a simple modification, then commit those changes.

You can change between branches by using just the checkout command -- if the branch already exists, do not use the -b flag when you checkout.

  $ git checkout master

This puts you back on the master branch, and if you look at the code, or run the git log command, you'll see all the changes in your new branch seem to be gone. But they're not really -- they're still safe in your new branch! Use checkout again to move between branches.

Saving your work without committing it

Every time you change branches, you take all the unstaged changes in your working directory with you to the new branch. Often this is undesirable, because the changes reflect things you're doing on a particular branch. In order to get around this, Git is going to help us out with git stash:

  $ git stash save "your message about what you're doing"

This takes the changes in your current working directory and hides them away in your stash; they disappear from the working directory, making it shiny and clean for you to move to another branch and work on something else. Once you're ready to come back, check out the branch you were working on and use

  $ git stash apply

to put the changes right back into your working directory, just like you never left. ;) Things can get a little complex in your stash if you've got several things you're working on. You can view a list of your stashes:

  $ git stash list

...and use the references from the list to tell Git what to diff:

  $ git diff stash@{0}

Merging

When it comes time to combine the changes on two branches, we use a merge. When we merge we always move the changes from the other branch to the branch we're currently on. Then we end up on the same branch with those new changes included. Our old branch still exists once the merge is done.

If our AO3-1234 branch is getting old and some other coders' changes have been merged into the AO3 codebase since we started working on it, we'll want to merge those changes into our branch, too. First we need to checkout and update our master branch:

     $ git checkout master
     $ git pull upstream master
     $ git push origin master

Then we'll want to switch back to our AO3-1234 branch and bring in all the new code that's on master:

     $ git checkout AO3-1234
     $ git merge master

Git picks the most sensible way to bring them together and creates another commit, called a merge-commit. Ta-da! Now AO3-1234 knows about the changes in master. If you look at the files, both sets of changes will be there.

Fixing merge conflicts

Except sometimes merges aren't quite so easy. As smart as Git is, there can still be problems when it comes time to do the merge -- for instance, if commit D and commit C both changed the same line in the same file. This doesn't happen a lot, but it does happen, and Git won't know how to merge those changes together. This creates a merge conflict. The first few times it happens, it can be confusing, but just take a deep breath and work through it.

When we have a merge conflict, we need to manually make sense of the changes and then tell Git what to do.

Git says:

     Auto-merging README.md
     CONFLICT (content): Merge conflict in README.md 
     Automatic merge failed; fix conflicts and then commit the result. 

It gives us a bit of an idea what to do when we open our README.md, where Git has left us some clues about what it's having trouble with:

     <<<<<<< HEAD
     Change on our master branch
     ======= 
     Change on our AO3-1234 branch 
     >>>>>>> AO3-1234 

It even shows us each file looked like. All we need to do is edit the file to look like we want it to end up. Remove all the arrows and == so that section ends up something like:

     Change to our README.md 

We've just resolved our conflict! Now to finish up, we need to tell Git that we've resolved it. We do this by staging and committing our fixed up README.md file:

     $ git add README.md 
     $ git commit -m "Resolved conflict in README.md" 

Git tells us then that it finished the merge. Done!

Cleaning up old branches

When we're done with our branch, it takes up some of our 'mental space' so we want to get rid of it. I don't usually do this right away, just in case, but eventually I get around to pruning down my branches to only those I'm working on.

Deleting branches that have been merged into master is easy:

    $ git branch -d AO3-1234 

This version will complain if your changes haven't been merged into master. If you don't care about the changes anymore (maybe you passed the bug on to someone else, or your attempt at the change ended up being totally wrong (it happens to us all)), and you just want to get rid of the changes whether or not they're merged, then you use this format:

    $ git branch -D AO3-1234 

The capital D flag forces the delete, and it won't complain about merging.

You'll need to push your changes if you want to remove the branch from your repository on GitHub:

    $ git push origin :AO3-1234

Collaborating

When we work on a project with many other contributors, like AO3, it's good to get reviews on our new code, and feedback from other developers. Sometimes others will have insights on why something doesn't work, or how to make the code simpler.

Sharing your work

The most straightforward way to share is by pushing your new branch up to GitHub and giving other devs the link to look at your changes. Since your GitHub fork is already known as origin to your working clone, this is very simple.

  $ git push origin AO3-1234

This will push the whole branch, and all the commits you've made to it up to GitHub; now let's go look at your branches and find the link.

https://github.com/USERNAME/otwarchive/branches will show you the master branch and all your other branches. It will show you who last updated the branches and when. It'll also tell you how many commits are on your new branch that aren't on master.

Click on a branch name to browse the code on that branch. The URL will be 'https://github.com/USERNAME/otwarchive/tree/AO3-1234

You can see what branch you're looking at on the upper left side of the screen (Branch: AO3-1234). You can also use this menu to switch to a different branch.

One nice thing about GitHub is that once you've pushed your branch, other devs can pull from your repository and get your branch and run your code on their development environment, all without disturbing any of the work they're doing.

Working on someone else's code

When someone else wants you to help them with their code, they need to push all their changes to GitHub and tell you the name of their branch.

The first thing you need do is add their fork as a remote repository:

   $ git remote add THEIRUSERNAME https://github.com/THEIRUSERNAME/otwarchive.git 

Then create a corresponding branch and pull in their code:

   $ git checkout -b AO3-4567
   $ git pull THEIRUSERNAME AO3-4567

After editing the files, commit your changes and push them to your own fork. The other person can then add your fork as a remote repository, pull in your code, make more changes, commit, and push.

Repeat pushing and pulling until the code is ready to be submitted to the main repository.

More References

There are far too many Git commands for us to look at them all here, but between this tutorial and the commands in AO3 Coding: Your First Pull Request, we've covered the main ones you are likely to need while working on OTW coding projects. Your favourite search engine will have many more detailed tutorials, as will these sites:

Helpful Tricks Senior stuff

What now?

Once you are comfortable with using Git, let's move on to Jira.