Blog

Handy Git script February 7, 2019


Preamble

If you're working with Git, especially with the command-line interface directly, you probably find yourself executing the same series of commands fairly frequently. Whether it's rebasing a current branch, starting a new one on top of the latest version of the code or cleaning-up a local repository, developers usually learn to view these mundane tasks as a necessary evil. I was no exception.

When working on projects, I usually work in my own fork, especially when other people are involved. Therefore, when I want to create a fresh new branch, I have to go through some git commands: git checkout master, git fetch --all, git rebase upstream/master, git push (I like to keep my fork up-to-date) and git checkout -b <new branch name>. Now, neither of these is particularly cumbersome. The whole process rarely even takes a minute. Still, it is very repetitive and a bit of a chore. One day, as I was waiting for an especially large change set to get fetched, I reflected on how ludicrous it was for me to still be doing this process "by hand". That's how I came to automate my way out of it:

Download script

Of course, as this is a fairly common problem, there are a number of similar scripts available online. Look around for the one that will make your life the easiest. Or maybe you have one of your own, or maybe you'll try your hand at it after reading this! Either way, it never hurts to look around for inspiration and seize the chance to learn something new in the process.

Usage

This is a .bat script, so Windows users only! After downloading it, place it in a folder that's listed in your global PATH variable to be able to use it everywhere. The script is best suited for people working in forks and using a different branch for everything. It also uses rebase instead of merge. Here's the full manual (also available in the script itself through the man command):

usage: git.bat <command> [-mlb <main local branch>] [-b <local branch>] [-r <remote>] [-rb <remote branch>] [-mb <main branch>]

# Commands
    checkout    stash, fetch --all, checkout <-mlb>, rebase <-r>/<-rb>, push, checkout -b <-b>
    rebase      stash, fetch --all, rebase <-r>/<-rb>
    cleanup     gc --quiet, remote prune origin, branch -D <pruned remote branches>, git branch -a

# Flags
    -mlb  Main local branch, defaults to "master"
    -b    Local branch, usually to be created
    -r    Remote from which to update, defaults to "upstream"
    -rb   Branch on the remote from which to update, defaults to "master"
    -mb   Main branch, sets the value of both the "-mlb" and "-rb" flags

# Examples
    git.bat checkout -b <new local branch>    
    git.bat rebase
    git.bat cleanup

Git
Last updated on February 7, 2019

— Etienne Lamoureux

Permalink

How to use GitHub October 14, 2018


So you want to use GitHub? Or maybe you have to, because it's your company's main repository. In any case, in this article I'll go in details on how to do just that, from the very beginning all the way to your first code contribution.

1. Install Git

First things first, if you want to use Git, you'll need it on your wprkstation. Head over to Git's download page and download the installer. Once the installer has finished downloading, simply run it and follow the instructions.

1.1 Windows

As Git is mainly a command-line tool, its installation can feel trickier on Windows. Luckily for Windows users, Git provides a neat installer to do all the work. Still, there are quite a few choices to make during the process and they came seems daunting at first. Let me walk you through the steps of the installer.

  • Select components screen
    • Recommended
      • Git LFS (Large File Support)
      • Associate .git configuration files with the default text editor
      • Associate .sh files to be run with the Bash
    • Optional
      • Windows Explorer integration: Useful if you don't like to navigate via the command line (using cd commands), this will add two options in the right-click menu of a folder to open the Git console and GUI.

Install Git, Select components screen

  • Choosing the default editor used by Git screen
    • Notepad++: If you don't have it already, you can download it from their download page.

Install Git, Choosing the default editor used by Git screen

  • Adjusting your PATH environment screen
    • Use Git from Git Bash only: This is the recommended option and should be the one you choose. Consider the other options only if you really require them. If you're unsure, you don't require them.

Install Git, Adjusting your PATH environment screen

  • Choosing HTTPS transport backend screen
    • Use the OpenSSL library: unless your organization requires you to use the Windows Secure Channel library, the default is recommended.
  • Configuring the line ending conversions, screen
    • Checkout Windows-style, commit Unix-style line endings: This is the option that will give you the least amount of trouble, so I recommend it. Unless you configure your code editor to properly manage Unix-style line endings, having Windows-style line endings will make your life easier. Whatever you do, do not choose Checkout as-is commit as-is, especially if you have team members working on Unix systems (lots of open source contributors use Unix systems).
  • Configuring the terminal emulator to use with Git Bash screen
    • Use MinTTY: The default works perfectly fine. Compared to Windows bash, it handles non-Unicode characters better and has colours (who doesn't like colours?).
  • Configuring extra options screen
    • Recommended
      • Enable file system caching
      • Enable Git Credential Manager
    • Optional
      • Enable symbolic links: If you're on Windows, chances are you're not using these very much. Not required.

2. Create a GitHub account

Now that you have Git installed on your local computer, it's time to create a GitHub account! Fill the sign-up form on their website. You may need to validate your email address to finish the registration process.

2.1 Join an organization

Organizations are groups of users (people) along with the repositories (projects) they contribute to. They are a common and convenient way to manage permissions and roles in a consistent manner across multiple projects. For example, if you look at the CakePHP organization, you will see that a team of about 40 contributors works on upwards of 60 repositories. They use the organization as a way to white-list people that have write permission on the important branches of their projects, such as the main development branch, the current release branch, etc.

If you want to contribute to projects inside an organization, make sure to request access to their administrator. This may not apply to you for now, but it might sooner than you think!

3. Setup your SSH key

You're signed-up, your email address has been validated and you're ready to code! Well, almost. There are two ways to work with Git: using HTTPS and using SSH. HTTPS is very convenient in that is doesn't require any additional setup and you could start working right away. The downside is that in order to authenticate you, GitHub will ask you for your credentials (username and password) again and again and again... To avoid this, I therefore recommend using SSH. To do so, you will need to generate a special signature unique to your workstation, your SSH key, and give it to GitHub so it knows it's you. Git will then automatically provide this key to GitHub every time you would need to authenticate, all on its own.

Follow the steps of the GitHub's SSH key setup guide and come back here when you're all done.

4. Clone the project

Alright, ready? Let's copy the source code of the project on your workstation! Actually, we'll do more than that: we will copy the entire repository, which consists of the source code AND all of its previous revisions, on your workstation! This is because, as opposed to other versioning system such as SVN, Git is completely decentralized. Every copy of the repository IS the full repository, meaning that even if the "master" copy on GitHub disappears, nothing is lost. To clone a project, follow these steps:

  1. Navigate to the project you want to clone in GitHub
  2. Click the green "Clone or download" button

How to clone a GitHub repository

  • Make sure the pop-up says "Clone with SSH". If it doesn't click the "Use SSH" link at the top-right of the pop-up

How to clone a GitHub repository using SSH

  1. Copy the string provided. It should start with git@
  2. Open your Git command-line or terminal
  3. Using cd commands, navigate to where you want to project's folder to be cloned to
    • Example: if you want the project to be in C:\workspace\java\<project>, navigate to C:\workspace\java
  4. Type git clone followed by the string you copied from GitHub and press Enter
    • If this is the first project you clone from GitHub, you will receive a warning about the fact that the authenticity of the host cannot be established. Verify that the host is in fact GitHub, and then press y, e, s, Enter

Git will then clone the repository to a folder with the same name as the project. The complete console log should look like this:

$ git clone git@github.com:<organization>/<project>.git
Cloning into '<project>'...
The authenticity of host 'github.com (192.30.253.113)' can't be established.
RSA key fingerprint is SHA256:<some long random-looking string>.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,192.30.253.113' (RSA) to the list of known hosts.
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1366 (delta 0), reused 0 (delta 0), pack-reused 1365
Receiving objects: 100% (1366/1366), 18.71 MiB | 5.79 MiB/s, done.
Resolving deltas: 100% (975/975), done.
Checking connectivity... done.
$ cd <project>

4.1 Fork the project

If you work on someone else's project, it is usually preferable to fork it before cloning it. Forking a project will simply copy the repository under your own namespace. It's a good idea to do so because it gives you your own copy of the project with which you can do as you please. It also has the benefit of restraining any screw-ups that might happen in your own copy, without any consequence to the main one.

To fork a project, simply navigate to the project's page on GitHub and click the "Fork" button (near the top-right), then select the namespace you want to fork it into (normally, your username's).

How to fork a GitHub repostory

Once you've forked the project, you can clone it as detailed in step 4 above. Then, proceed to step 4.2: Add a remote.

4.2 Add a remote

A remote is a link between your local version of the repository and a fork that isn't your own. For example, if you forked the main repository into your own namespace and then cloned that fork, you should add the main repository as a remote to be able to stay up-to-date with the changes happening there. To add a remote to your local repository, run the following command:

$ git remote add --track <main branch on remote> <local name of remote> git@github.com:<organization>/<project>.git

Where:

  • <main branch on remote> is the name of the branch you wish to track locally. Must exist in the parent repository.
  • <local name of remote> is the name you are going to give to the parent repository on your workstation. It's entirely up to you. I like to use upstream for the main remote.
  • git@github.com:<organization>/<project>.git is the string you would use to clone the parent repository (from the green "Clone or download" button)

*For more information, see Git's documentation on remotes.

Example:

$ git remote add --track master upstream git@github.com:<organization>/<project>.git
$ git remote
origin
upstream

5. Create a new branch

Working in a branch separate from the main one helps keeping things clean and organized. It also helps to easily be able to go back to a stable version of the code. When using feature-branches with Git, a new branch should be created for every single change you wish to make, no matter how small. To create a new branch, follow these steps:

  1. Make sure your local repository is up-to-date
    • If you work directly on the main repository, simply run:
      • git fetch --all to get any new changes from the main repository you might not have locally
      • git checkout origin/master to jump to the latest stable commit
    • If you work in your own fork, run:
      • git fetch --all to get any new changes from the main repository you might not have locally
      • git checkout master to go to your main local branch
      • git rebase upstream/master to apply the changes from the main repository to your local one
  2. Create a new branch using the git checkout -b <new branch name> command
  3. Code!

6. Commit often

Committing changes into Git is akin to pressing the "Save" button in a text editor: you should do it all the time. It's almost impossible to lose work once it's been committed into Git. So, since you don't want to lose work, commit often! Don't worry about messy commits: you can always amend the last commit to fix it later or even squash multiple commits together to tidy it up. Don't let that hinder you from committing often. To commit changes into Git, simply follow these instructions:

  1. Open your Git command-line or terminal
  2. Using cd commands, navigate to your project's folder
  3. Run the git gui command
  4. Click the "Rescan" button to allow the UI to pick-up your latest changes
  5. Stage the changes you want to commit from the top-left pane to the bottom-left pane by selecting them and pressing Ctrl+t
    • You can Ctrl+click or Shift+click the files
  6. Write a clear and concise commit message on the first line, leaving the details to the next lines if required
  7. Press the "Commit" button

How to commit using Git

6.1 Rebase often

If you work on a project as a member of a team, changes will constantly be merged into the main repository while you're working on yours. If you wait too long before syncing your local repository with the changes from the main repository, the code you're working on might end-up needing some serious adjustments or could even not be required anymore! To keep up with the changes, I recommend rebasing at least daily, depending on the size of your team and the frequency at which changes are merged into the main repository. To rebase, run:

  1. git fetch --all
  2. git rebase upstream/master
  3. Fix the resulting conflicts, if any

7. Push

Once your changes are ready, you can send them to GitHub using the push command. This will update the repository on GitHub with the changes that are currently only in your local repository. To push, simply run the git push command. If this is the first time you're pushing the branch, Git will let you know that you have to add some flags to the command. Copy the command given by Git and push your changes. The complete console log should look like this:

$ git push
fatal: The current branch <branch name> has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin <branch name>

$ git push --set-upstream origin <branch name>
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:<organization>/<project>.git
 * [new branch]      <branch name> -> <branch name>
Branch <branch name> set up to track remote branch <branch name> from origin.

8. Create a pull request

You've done it: you've created a new change set in a branch! Ready to request to the repository administrator to take your contribution? Alright, first of all, head to GitHub and navigate your way to the main repository's page. Next, you will see a new yellow alert that wasn't there before. It will look like this:

GitHub pull request button

Click the "Compare & pull request" button. This will bring you the pull request submission form. That form is divided into different parts:

GitHub pull request form

Let's take a look at them. At the top is the title of your pull request. Keep in mind the tips shared above about the first line of the commit message: the pull request title should respect those too. Once that's filled out, it's a good idea to describe what you did, at a high level, into the comment field. Add any important details you can think of and also any links to issues or tickets fixed or impacted by your pull request. Having cross-references make it much easier to go back and track the reason why certain changes happened.

Then there's the right sidebar. Its first section is to request reviews. I recommend all pull requests to be reviewed. By whom? Well that depends, but a good rule of thumb should be to assign pull requests to people that are intimately familiar with the area of the code you changed. They are the ones that will be able to make the most insightful comments about your changes. Those experts will also be able to tell you if you broke some fundamental assumption of the code that you might not have known about. In any case, always having at least one review never hurts. The second section is about the assignee. That person is the one that is responsible to formally accept your pull request into the repository. When you've filled everything, finish by clicking the green "Create pull request" button.

There you go, you got through it all! Through this tutorial we've seen how to get the code base of a project from GitHub to your computer, how to stay up-to-date with the other contributors and finally, how to push your changes back to the master repository. Feel free to come back this page if need be: the commands never change and having a reference sheet is always handy. There is much more to learn about Git and GitHub but for now: go on and contribute!


Git Tutorial
Last updated on February 7, 2019

— Etienne Lamoureux

Permalink

Dynamically change CakePHP language January 30, 2014


or how to control the locale of a CakePHP 2.x application by a parameter in the URL

Preamble

When I made the previous version of this website, I encountered a problem to which i found no satisfactory solution online: how to easily change the language of a CakePHP application. The framework's documentation itself doesn't help much, saying only:

There are several ways to do this, it can be by using language specific subdomains (en.example.com, fra.example.com, etc.), or using a prefix to the URL such as is done with this application. You may also wish to glean the information from the browser’s user-agent, among other things.

This is all well and good, but how to actually do it? And more importantly, how to do it in an elegant way, without polluting the entire application? Although Dorin Moise has managed to do something that works, the comments under his post suggest that a better solution is possible. In addition, the code managing the language change is mixed with AppController. When there is no satisfactory solution, the only thing left is to create one yourself! I invite you to check my complete solution on GitHub. The rest of this post will detail how to integrate the solution.

Installation Details

The heart of the module is located in the component LanguageComponent. To start, you must add the file in the Component folder in this location:

app/Controller/Component/LanguageComponent.php

Then, include the class in the application controller. In its definition, give the LanguageComponent the list of languages ​​supported by your application. Note that the array key can be anything you choose. However, note that this is the value that will be used to recognize the language parameter in the URL. For the associated value, you must use an ISO 639-2 locale code. Here is an example:

app/Controller/AppController.php

public $components = array(
    'Language' => array(
        'supportedLanguages' => array(
            'en' => 'eng',
            'fr' => 'fra'
            ),
        )
);

Once the component included in the project, make sure that the links with language parameters are properly managed by the application. First, to ensure that the language is part of all the links in your application, you must redefine two functions:

app/Controller/AppController.php

public function redirect($url, $status = NULL, $exit = true)
{
    if (is_array($url) && !isset($url['language']))
    {
        $url['language'] = $this->Language->getLanguage();
    }

    parent::redirect($url, $status, $exit);
}

app/View/Helper/AppHelper.php

public function url($url = null, $full = false)
{
    if(is_array($url) && !isset($url['language']))
    {
        $url['language'] = $_SESSION['Config']['languageCode'];
    }

    return parent::url($url, $full);
}

Now that the user is always redirected to a page that contains the language in the URL, you must define this language parameter in your application's routes. This will require to modify the routes.php file like this:

app/Config/routes.php

//user-defined language codes here, must be same ones used for the LanguageComponent
$languageCodes = array('language' => 'en|fr');

Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
Router::connect('/:language', array('controller' => 'pages', 'action' => 'display', 'home'), $languageCodes);

Router::connect('/:language/pages/*', array('controller' => 'pages', 'action' => 'display'), $languageCodes);

//default cakePHP routing, with language codes
Router::connect('/:language/:controller/:action/*', array(), $languageCodes);
Router::connect('/:language/:controller', array('action' => 'index'), $languageCodes);

For safety, add a default locale for your application by defining it in core.php:

app/Config/core.php

/**
 * Application default locale
 * Must use an ISO 639-2 locale code
 */
Configure::write('Config.language', 'eng');

For everything to work automatically, there are two more changes to do to the application controller. The first changes the locale of your application using this language parameter in the URL. The second gives you access to the current language of your application in all your views. Here they are:

app/Controller/AppController.php

public function beforeFilter()
{
    $this->Language->set($this->params['language']);
}

function beforeRender()
{
    $this->set('language', $this->Language->getLanguage()); //to access the language code from any view
}

And voilà! The current language code is available in all your pages using the variable $language. To add a language-changing link to your pages, just add the language option in the options array $options = array() of a link created by HtmlHelper::link. For example:

echo $this->Html->link('Français', array('language'=>'fr'));

CakePHP Internationalization PHP
Last updated on October 14, 2018

— Etienne Lamoureux

Permalink