How to replace text everywhere in Git

There is a Git command, filter-branch, which works wonders for changing the history of a repository, but it’s difficult to use because it forces you to know how Git works under the hood. Instead there is this little free tool, BFG Repo-Cleaner, which is intuitive, fast and recommended.

Check that there are some occurrences of your string

The first thing to do is to check that the repository contains the string you want to replace with another string. This will help later to make sure you effectively replaced it.

andrea at Lock-and-Stock in ~/dev/ruby
$ git clone git@gitlab.com:aercolino/your-repository.git

andrea at Lock-and-Stock in ~/dev/ruby
$ cd your-repository

andrea at Lock-and-Stock in ~/dev/ruby/your-repository
$ git log -G"your string" -i --all
commit ...
Author: ...
Date:   ...

    Message 2

commit ...
Author: ...
Date:   ...

    Message 1

Notice that, on the above git log line, the -G option allows to specify a regular expression, and the -i option allows to  ignore case.

Install BFG

BFG needs a JVM and you can install one with brew on a Mac.

$ brew cask install java
$ brew install bfg

Create search-replace.txt

BFG takes a file for specifying the text to search and replace. The accepted format is one replacement per line, like SEARCH==>REPLACE, with optional prefixes regex:, and glob:.

regex:your string==>another string

Use BFG

BFG acts on a bare repository which you can get by cloning with the --mirror option. Make sure the last commit doesn’t contains the text to be replaced, otherwise add a clean commit and push it before cloning.

andrea at Lock-and-Stock in ~/dev/ruby
$ git clone --mirror git@gitlab.com:aercolino/your-repository.git

andrea at Lock-and-Stock in ~/dev/ruby
$ bfg --replace-text search-replace.txt your-repository.git

andrea at Lock-and-Stock in ~/dev/ruby
$ cd your-repository.git

andrea at Lock-and-Stock in ~/dev/ruby/your-repository.git
$ git reflog expire --expire=now --all && git gc --prune=now --aggressive

Backup the old your-repository

You can recover this backup analogously to the section below.

andrea at Lock-and-Stock in ~/dev/ruby
$ git clone --mirror git@gitlab.com:aercolino/blog-experiment.git blog-experiment.git.backup

Create a new your-repository

This step involves removing your remote old repository and creating a remote new one with the same name as before. Then you can push to it from your local repository using the --mirror option.

andrea at Lock-and-Stock in ~/dev/ruby/your-repository.git
$ git push origin --mirror

Check that your string was replaced by another string

If all is OK then you should see no results when searching again for your string but at least the same number of results you got when looking for it before if you now look for the replacement string.

andrea at Lock-and-Stock in ~/dev/ruby
$ git clone git@gitlab.com:aercolino/your-repository.git

andrea at Lock-and-Stock in ~/dev/ruby
$ cd your-repository

andrea at Lock-and-Stock in ~/dev/ruby/your-repository
$ git log -G"your string" -i --all
(nothing shown)
andrea at Lock-and-Stock in ~/dev/ruby/your-repository
$ git log -G"another string" -i --all
commit ...
Author: ...
Date:   ...

    Message 2

commit ...
Author: ...
Date:   ...

    Message 1

 

How to install WordPress with Docker on OS Sierra

With individual Docker commands

  1. Install Docker for Mac
  2. $ docker run –name mysql-latest -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:latest
  3. $ docker run –name wordpress -p 8000:80 –link mysql-latest:mysql -d wordpress:4.7.3-php7.1-apache
  4. Visit http://0.0.0.0:8000 and configure WordPress

With a Docker compose file

  1. Install Docker for Mac
  2. Save the following text to a ´~/dev /wordpress /website /docker-compose.yml´ file:
    version: '2'
    
    services:
      dbms:
        image: mysql:5.7
        volumes:
          - db_data:/var/lib/mysql
        ports:
          - 32768:3306
        restart: always
        environment:
          MYSQL_ROOT_PASSWORD: wordpress
          MYSQL_DATABASE: wordpress
          MYSQL_USER: wordpress
          MYSQL_PASSWORD: wordpress
    
      wordpress:
        depends_on:
          - dbms
        build: ./docker/wordpress
        image: wordpress:xdebug
        volumes:
          - .:/var/www/html
        ports:
          - 8000:80
        restart: always
        environment:
          WORDPRESS_DB_HOST: dbms:3306
          WORDPRESS_DB_PASSWORD: wordpress
          XDEBUG_CONFIG: remote_host=192.168.1.33
    
    volumes:
        db_data:
  3. Save the following text to a ´~/dev /wordpress /website /docker /wordpress /Dockerfile´ file
    FROM wordpress:4.7.3-php7.1-apache
    
    RUN yes | pecl install xdebug 
        && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > /usr/local/etc/php/conf.d/xdebug.ini 
        && echo "xdebug.remote_enable=on" >> /usr/local/etc/php/conf.d/xdebug.ini 
        && echo "xdebug.remote_autostart=off" >> /usr/local/etc/php/conf.d/xdebug.ini
  4. Run everything: ´$ docker-compose up´
  5. Visit http://0.0.0.0:8000 and configure WordPress

Connect to the running dbms server from SequelPro

  1. Select the Standard tab
  2. Configure:
    Name: Docker for WordPress
    Host: 0.0.0.0
    Port: 32768
    Username: wordpress
    Password: wordpress
  3. Connect

Connect to a running server from a terminal

Example relative to connecting to the running dbms server.

  1. Find out the name of the server:
    $ docker-compose ps
           Name                      Command               State            Ports
    --------------------------------------------------------------------------------------
    website_dbms_1        docker-entrypoint.sh mysqld      Up      0.0.0.0:32768->3306/tcp
    website_wordpress_1   docker-entrypoint.sh apach ...   Up      0.0.0.0:8000->80/tcp
  2. Connect to the ´website_dbms_1´ server:
    $ docker exec -it website_dbms_1 bash
    root@7d36d19c7df4:/#
  3. Then, for example, find out the server IP:
    root@7d36d19c7df4:/# hostname -I
    172.18.0.2

How canActivate works for multiple guards

Angular 2 lets developers forbid routes activation by means of a list of guards assigned to the canActivate property of a route definition.

{ 
  path: 'vip-lounge', 
  component: 'VipLoungeComponent', 
  canActivate: [ IfUserIsLoggedIn, 
    AndSpendsEnough,
    AndMembershipIsCurrent ]
}

Those guards are classes which implement the CanActivate interface, and the implementation can be a promise, for example when it entails a roundtrip to the server.

The way Angular 2 treats this list of guards is by applying .every(...) to the values of a merge-mapped list of observables.

  checkGuards(): Observable<boolean> {
    if (this.checks.length === 0) return of (true);
    const checks$ = from(this.checks);
    const runningChecks$ = mergeMap.call(checks$, (s: any) => {
      if (s instanceof CanActivate) {
        return andObservables(
            from([this.runCanActivateChild(s.path), this.runCanActivate(s.route)]));
      } else if (s instanceof CanDeactivate) {
        // workaround https://github.com/Microsoft/TypeScript/issues/7271
        const s2 = s as CanDeactivate;
        return this.runCanDeactivate(s2.component, s2.route);
      } else {
        throw new Error('Cannot be reached');
      }
    });
    return every.call(runningChecks$, (result: any) => result === true);
  }

The list of guards is conceptually the same as a list of promises, and in fact all the guards could be promises because, as we see above, .from(...) is used to initialise check$.

Merge-mapping is exactly what we did in How to convert promises to an observable.

var source = Rx.Observable.from(promises.map(function (promise) { 
  return Rx.Observable.from(promise); 
})).mergeAll(); 
/* 
 
true 
"Next: true" 
true 
"Next: true" 
true 
"Next: true" 
false 
"Next: false" 
true 
"Next: true" 
"Completed" 
 
*/

var source = Rx.Observable.from(promises).mergeMap(function (promise) {
  return Rx.Observable.from(promise);
});
/* 
 
true 
"Next: true" 
true 
"Next: true" 
true 
"Next: true" 
false 
"Next: false" 
true 
"Next: true" 
"Completed" 
 
*/

If we now apply .every(...) to that merge-mapped list of promises, we can see how canActivate works for multiple guards.

var source = Rx.Observable
  .from(promises)
  .mergeMap(promise => Rx.Observable.from(promise))
  .every(value => value === true);
/*

true
true
true
false
"Next: false"
"Completed"
true

*/

Notice that the subscription is notified only once, as soon as the resolved promises make it clear what the result would be: the observable emits a false soon after getting the first false, or a true after getting all true-s. So, as expected, canActivate works as a short-circuit-ed AND of each guard of the list, according to the arrival order of values.

Also notice that the values of all the promises keep arriving as promises get resolved, even after the observable has completed. This means that guards intended to be used together in a list of guards should never have side effects (to avoid race conditions). If guard G1 had a side effect of activating route R1, and G2 had another for R2, then canActivate: [G1, G2] would unpredictably activate R1 or R2, depending on which guard completes later.