Basic Git/GitHub for Localizers

Table of Contents

Basic Usage

Advanced Usage

Final Suggestions

Basic Usage

Fork A Repository On GitHub

If you don’t have an account on GitHub, register one for free on github.com and install Git on your system.

Once you login, go to the repository you’re interested in and create a “fork”. Let’s say you want to create a fork of webpay: go to github.com/mozilla/webpay and click on the Fork button in the top right part of the page.fork

This will create a fork – think of it as a copy – of the webpay repository in your own account. At this point your fork and the original repository share the same history, but will live separate lives from this moment on.

Fork and Original Repo

Clone Your Repository

Now you have to clone the repository on your computer. Suppose that your username is l10nguy, you need to clone https://github.com/l10nguy/webpay and tell the system that you want to use the original Mozilla repository as a source for updates.

These are the commands you need to run in your terminal (move into the folder where you want to keep your files before running them):

# You’re cloning your forked repository, so github.com/YOURUSER/REPOSITORY
git clone https://github.com/l10nguy/webpay

# Move in the clone’s folder created by the previous command
cd webpay

# You’re telling Git to use another repository as a source.
# So not YOURUSER but MOZILLA in this case (owner of the original repository)
git remote add upstream https://github.com/mozilla/webpay

Sync And Update Your Repository

Now you have a local copy of your fork inside the folder webpay. Remember: your fork and the original source are now two separate entities. Suppose someone made a new commit on master to the original repository after you forked it: this commit won’t be automatically available in your fork.

Original repo with new commit

When you want to update your local copy, importing new changes from the original repository, you need to run these commands from inside the repository (i.e. the webpay folder).

# Important: the following line will delete every local change. It’s useful to
# avoid conflicts and merges, if you know what you’re doing you can ignore it
# Stashed changes can be recovered: see http://git-scm.com/docs/git-stash
git stash

# Ensure that you’re on the branch called Master
git checkout master

# Pull changes from Mozilla’s repositories, merge to your repository and push
# changes to Github. We told Git what "upstream" is right after cloning
# the repository.
git fetch upstream
git merge upstream/master
git push

Provide your GitHub’s credentials and the updates will be pushed to your GitHub’s repository.

Note: you could get this error the first time you try to push:

warning: push.default is unset; its implicit value is changing in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:

  git config --global push.default matching

To squelch this message and adopt the new behavior now, use:

  git config --global push.default simple

To fix it and adopt the new default behavior, simply run the last command from the command prompt (more details here).

git config --global push.default simple

Create A Pull Request

As a first step you need to create a branch in your repository, so you’ll have to choose a name for it. For example let’s call this branch jul29_it

You should never commit changes to master, since it will create merge conflicts when trying to update against the original (upstream) repository.

# Create the branch
git branch jul29_it

# Ensure that you’re on the branch just created
git checkout jul29_it

# Push the new branch to your repository on GitHub
git push origin jul29_it

This is the result:

New branch on fork

At this point your local files are on the branch called jul29_it. You can always check the current branch or the files modified by running git status:

On branch jul29_it
nothing to commit, working directory clean
        

Update the files and, when you’re ready, commit your changes using these commands. In this case I’m updating Italian and the file is locale/it/LC_MESSAGES/messages.po (side note: don’t commit .mo files, they’re compiled from .po and not necessary).

# Add the updated file to the commit
git add locale/it/LC_MESSAGES/messages.po

# Commit with a meaningful message
git commit -m "Updated Italian localization"

# Push changes to GitHub
git push origin jul29_it

At this point your branch will be one commit ahead of master.

New branch with commit

Now you can go to your forked repository on GitHub and you will see something like this.

pr

Click on the button Compare & pull request, check the pull request (you can see the diff at the bottom of the page) and if everything looks good click on the green button Send pull request to complete the procedure. pr You’ll receive an email when the pull request is merged into the project, or if there’s a problem with the pull request and someone added a comment. If necessary, you can modify or close your pull request from the project’s pull requests list (select your pull request, the Close button is at the end of the screen). pr

Advanced Usage

Rebase Your Branch

Let’s consider the following situation: your master and the upstream’s master are in sync, on top of the history there’s “COMMIT B”. You created a branch called “TEST1”, made some changes and committed. In the meantime, someone has pushed a new commit to the upstream’s master.

New branch with commit

If you’re lucky, “COMMIT C” and “COMMIT X” won’t have any conflicts and your PR can be merged. If the two commits touch the same file, you’ll probably need to rebase your branch to be able to merge the pull request.

The first thing you need to do is to update your master, and sync with upstream.

# Switch to master
git checkout master

# Update your master, push changes to repo
git fetch upstream
git merge upstream/master
git push

# Go back to your branch
git checkout test1
        

Now you’re in the following condition: master looks up to date, but your branch is still missing “COMMIT C”.

Master rebased

Let’s rebase against master:

git rebase master

If there are conflicts, you’ll get a message similar to the following:

First, rewinding head to replay your work on top of it...
Applying: Commit X
Using index info to reconstruct a base tree...
M   test.txt
Falling back to patching base and 3-way merge...
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Failed to merge in the changes.
Patch failed at 0001 Commit X
The copy of the patch that failed is found in:
   /Users/flodolo/Desktop/testdoc/.git/rebase-apply/patch

When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
        

Git is unable to merge the conflicts, so you need to manually fix the issue. In this case the file is called test.txt, and its content will look like this

<<<<<<< HEAD
First commit
=======
First real commit
>>>>>>> Commit X
        

Before ======= there’s the text from master, below the text from the branch’s commit. At this point you can fix the merge conflict, tell Git to include the file, continue the rebase and force push to the remote repository.

git add test.txt
git rebase --continue
        

If you haven’t already pushed your commits to GitHub, you can use git push. Otherwise you’ll need to do a forced push with git push -f, since since you’re rewriting history.

This is the result of rebasing against master. Branch rebased

Never use a forced push on a shared repository or a shared branch. It will rewrite history, and any change not available in your local repository will be deleted.

Reset Your Branch

Making mistakes is easy. For example, you committed to your master instead of using a branch. How do you recover from that? You can reset your repository to a different state.

For example, let’s assume that you committed your changes to master, and want to go back. One thing that you could is to reset your repository to the same state of the origin’s master (remember, origin is your repository, the one your clone originated from).

git reset --hard origin/master

If you already pushed your changes to master, you can always reset to upstream’s master

git reset --hard upstream/master

If you want to remove extra-files (not tracked by Git) you can run:

git clean -fd

Amend The Last Commit

You committed some changes to your repository, but realized that you made a mistake and want to fix it without creating a new commit.

Make the needed changes like you would do for a normal commit, but at the end run git commit with the --amend parameter:

git commit --amend

Don’forget to add the files to your commit before running git commit. It’s also possible to add all files, but always double check what you’re committing.

git commit -a --amend

You’ll be asked to confirm the new commit message. If you haven’t already pushed your commits to GitHub, you can use git push. Otherwise you’ll need to do a forced push with git push -f, since since you’re rewriting history.

Squash Your Commits

Sometimes you’ll be asked to squash your commits. Let‘s say you created a new branch in your repository, and the tip of your branch has a message “Last commit on master”.

git log -n 1
commit 08bff51037bc12362a986049d9feabda120933f0
Author: Francesco Lodolo (:flod) 
Date:   Fri May 8 08:16:24 2015 +0200

    Last commit on master
        

You made a first commit to update a file, then realized that you made a mistake and added a second commit to fix the error instead of amending your last commit.

git log -n 3
commit 3e086e54673229fa5a3c8fe08b77b45482151b3f
Author: Francesco Lodolo (:flod) 
Date:   Fri May 8 08:18:45 2015 +0200

    Fix Typo

commit 496ff879e92998971a8e2c886fa20be3e29cfb2b
Author: Francesco Lodolo (:flod) 
Date:   Fri May 8 08:18:32 2015 +0200

    Add new String

commit 08bff51037bc12362a986049d9feabda120933f0
Author: Francesco Lodolo (:flod) 
Date:   Fri May 8 08:16:24 2015 +0200

    Last commit on master

This is how your branch currently looks like.

pr

When merged, both commits will be available in the history of the main repository, making it less readable and useful. To collapse the last 2 commits you can run this command:

git rebase -i HEAD~2

You’re asking git to rebase interactively your branch, changing the last 2 commits from the HEAD of the branch (to squash 3 commits change to HEAD~3, etc.). You’ll be presented with a screen like this one

pick 496ff87 Add new String
pick 3e086e5 Fix Typo

# Rebase 08bff51..3e086e5 onto 08bff51 (2 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
        

You need to tell Git that you want to keep the oldest commit (first in the list), and squash the more recent commit. You could also decide to reword a commit if needed. To squash the commits change the first two lines like this, save and continue.

pick 496ff87 Add new String
squash 3e086e5 Fix Typo
        

Then you’ll be asked to confirm the commit message (it will automatically present you with the commit message of both commits). This is how the log will look like after squashing the commits.

git log -n 2
commit 8cf7d79f8345d513b878467c8e1f71f88a1c5e2b
Author: Francesco Lodolo (:flod) 
Date:   Fri May 8 08:18:32 2015 +0200

    Add new String

commit 08bff51037bc12362a986049d9feabda120933f0
Author: Francesco Lodolo (:flod) 
Date:   Fri May 8 08:16:24 2015 +0200

    Last commit on master
        

If you haven’t already pushed your commits to GitHub, you can use git push. Otherwise you’ll need to do a forced push with git push -f, since since you’re rewriting history.

Bash Tips

It’s very useful to display in your command line the current branch when you’re in folder containing a Git repository. You can obtain this by adding some lines to your configuration file.

Linux

Add these lines at the bottom of .bash_rc in your home folder

alias ls='ls --color=auto'
PS1="\[\e[1;32m\][\u@\h \W]\$(parse_git_branch)\[\e[0m\] "

function parse_git_branch () {
       git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
        

OS X

Add these lines at the bottom of .bash_profile in your home folder

export PATH=/usr/local/git/bin:$PATH

# Colors in Terminal
export CLICOLOR=1
export LSCOLORS=GxFxCxDxBxegedabagaced

# Git branch in prompt.
parse_git_branch() {
    git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/ (\1)/'
}
export PS1="\u@\h \W\[\033[32m\]\$(parse_git_branch)\[\033[00m\] $ "
        

Final Suggestions

Note: this doc is available on GitHub. If you want to improve it, you should know how do it now ;-)

Last updated: 2015-05-08