Basic Git/GitHub for Localizers
Table of Contents
Basic Usage
- Fork A Repository On GitHub
- Clone Your Repository
- Sync And Update Your Repository
- Create A Pull Request
Advanced Usage
Final SuggestionsBasic 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.
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.
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.
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:
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.
Now you can go to your forked repository on GitHub and you will see something like this.
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.
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).
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.
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”.
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.
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.
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
- If something goes wrong, you can always delete your forked repository and start from scratch, or return to the branch Master (see Update section) and create a new clean branch to start from. As a personal suggestion, don’t ever commit to Master, just create new branches for your own changes.
- Always update your forked repository before creating new branches.
- If you create a pull request from the branch jul29_it and push other commits to the same branch, the pull request will be automatically updated. In other words: if you don’t want to change your original pull request, don’t push to that branch until the pull request is approved and merged.
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