GIT Add Enviando Arquivos para Staging Area

CommandNew FilesModified FilesDeleted FilesHidden FilesDescription
git add -A✔️✔️✔️✔️Stage all files from top till down folders
git add .✔️✔️✔️✔️Stage all files under current folder and all subfolders
git add *✔️✔️✔️Same as git add . but excludes hidden files
git add –ignore-removal .✔️✔️✔️Same as git add . but excludes deleted files
git add -u✔️✔️✔️Same as git add -A but excludes untracked files
git add -A .✔️✔️✔️✔️Same as git add .
git add -u .✔️✔️✔️Mixes git add . and git add -u means it works under current folder and its subfolders only
git add $(git ls-files -o –exclude-standard)✔️Stage only untracked files from top till down folders

O comando git add é bastante versátil e suas opções permitem adequar seu comportamento conforme a necessidade do momento.

Isto é bom do ponto de vista de funcionalidade pois apenas adicionando flags podemos ajustar para o melhor resultado. Do ponto de vista de memorização pode ser um pouco complicado até que você consiga vincular as flags necessárias com o comportamento esperado.

Resolvi fazer um tabela no estilo CheatSheet para poder consultar rapidamente sempre que precisar relembrar uma combinação.

Quando estiver em dúvida que opção usar, lembre que você pode usar o bom e velho caminho completo para incluir um único arquivo.

git add full/path/to/my/file/from/current/folder.file

E aí? Vai uma CheatSheet?!

GIT Reset Eliminando um Commit da sua Branch

-- before proceeding be sure working area is clean
git status 

-- eliminate commit and throw away all changes
git reset --hard HEAD~1

-- or if you want to reuse your changes
-- eliminate commit but keep changes at working area
git reset --soft HEAD~1

Em algumas situações acabamos por introduzir um commit indesejado numa branch. Então o que fazer?

Fácil, o RESET está aí pra isso mesmo.

Usando a opção –hard estamos indicando que as alterações desfeitas sejam jogadas fora, ou seja, você usa esta opção quando desistiu mesmo e quer recomeçar o trabalho do zero.

Já a opção –soft estamos indicando que as alterações desfeitas permaneçam nos arquivos da working area para que você possa ainda utilizá-los antes de um novo commit.

Vale lembrar que estamos sacando fora commits do topo da pilha. Na verdade podemos sacar vários commits de uma só vez mas sempre será a partir do topo e em sequência.

-- eliminate the top 5 commits in the stack at once
git reset --hard HEAD~5

Para sacar mais de um commit por vez basta ajustarmos o HEAD~{n} onde n é a quantidade de commits a serem removidos.

É isso, mais fácil que cortar manteiga quente!

GIT Reset Para Unificar Vários Commits em um Único Commit

git reset --soft HEAD~2 
git commit -m "new commit message"
git push -f

O jeito mais rápido para se unificar vários commits num único commit é usando o git reset. Pra quem não sabe o nome desta operação é SQUASH, mas o GIT não tem uma comando git squash como muitos podem pensar.

Apesar de muitos artigos desaconselharem o uso do RESET por vários motivos, esta sequência de comandos é inofensiva e muito fácil de realizar.

No exemplo acima basicamente o reset desfaz os últimos 2 commits indicados em HEAD~2 sendo que o –soft indica para manter os arquivos impactados na working area.

Na sequência basta realizar um novo commit com todos os arquivos contendo as alterações dos commits desfeitos. Uma nova mensagem precisa ser informada para este novo commit.

Simples, rápido e eficiente!

GIT Rebase para Trabalhar numa Branch dependente de Outra Branch

-- start branch2 from branch1
git checkout branch1
git checkout -b branch2

-- make changes on branch2
git checkout branch2
git add file-changed
git commit -m "my commit message"

-- rebase branch2 whenever branch1 gets changed
git checkout branch2
git rebase branch1

-- finally rebase branch2 after branch1 was merged into master
git checkout master
git pull origin master
git checkout branch2
git rebase --onto master branch1 branch2

Trabalhando com as diversas técnicas modernas de desenvolvimento de sistemas como CI/CD, CleanCode, PMF entre outras os Web Devs frequentemente enfrentam o dilema de fragmentar ou não seus Pull Requests.

Para quem trabalha com o GIT segue aqui uma receita que achei interessante registrar. A receita é auto-explicativa não tem muito segredo; a sacada aqui é a sequência combinada dos comandos que já utilizamos em atividades diárias com o GIT.

Quer saber se funciona mesmo?

Funciona sim, finalmente tive oportunidade de testar num projeto recente e foi sucesso total, exceto pelo fato de eu ter produzido múltiplos commits o que não é permitido no meu ambiente de CI/CD.

Para resolver estes commits múltiplos bastou fazer um squash para unificá-los na branch final.

git checkout branch2
git reset --soft HEAD~2
git commit -m "new commit message"
git pull --rebase origin master --autostash
git push -f

Para evitar essa complicação final deveríamos fazer apenas commits complementares, assim logo após criar a branch2 a partir da branch1 somente performar commitamend:

-- make your changes on branch2 then commit amend
git checkout -b branch2
git add file-changed
git commit --amend

So, who’s gonna take the risk?

MySQL Contando Registros com Múltiplas Condições

SELECT COUNT(id) AS count_total
     , SUM(IF(message = 'content1',1,0)) AS count_message1
     , SUM(CASE 
              WHEN message LIKE 'content1' THEN 1 ELSE 0
           END) AS count_message1a
FROM mytable;

Sempre que precisamos observar e analisar dados podemos fazer uso de comandos mais avançados de SQL.

É claro que este meu exemplo está longe de ser um SQL complexo, mas sempre é bom deixar registrado as possibilidades a partir de um ponto simples também.

Neste caso estou fazendo uma contagem total de registros da tabela com o COUNT(id) simples, como nenhuma condição foi posta no WHERE serão contados todos os registros.

Então quero comparar lado a lado este total de registros com o total de mensagens do tipo 1. Para obter esta contagem parcial precisamos combinar o SUM() com um IF() interno condicionando a contagem apenas para as mensagens com o conteúdo que combinem com o que eu quero.

Opcionalmente ao IF() podemos utilizar a instrução CASE(); o resultado será o mesmo, apenas estamos utilizando uma sintaxe diferente.

É claro que a instrução CASE() vai ter melhor aplicabilidade em determinadas situações, assim como o IF() também tem sua aplicação para funcionalidades de menor complexidade.

Fica a seu critério qual sintaxe aplicar; este é só o ponta-pé inicial na utilização de SQL para análise de dados.

Souriez s’il vous plait!

MySQL Resetar Sequência AutoIncrement Sem Informar Próxima Sequência

-- first, remove auto-increment attribute if it still exists
ALTER TABLE `mytable` MODIFY COLUMN `id` INT(10) UNSIGNED;

-- second, add auto-increment attribute back
ALTER TABLE `mytable` MODIFY COLUMN `id` INT(10) UNSIGNED AUTO_INCREMENT;

Recentemente enfrentei um problema de deixar os cabelos em pé onde uma das tabelas acabou perdendo o atributo auto-increment durante uma operação de movimentação na nuvem.

Bom, o deixar os cabelos em pé foi por que demorei muito para descobrir a ocorrência deste evento de perda do atributo, porém a correção do schema é bastante simples.

Apesar do meu caso se tratar de uma tabela de pouca movimentação eu quis utilizar uma solução que encontrei durante minhas buscas. Achei esta solução bastante interessante pelo fato de não ser preciso atribuir o valor do auto-increment com um HARD SET utilizando o MAX VALUE da coluna id correntemente na tabela.

Ao invés disto, a operação consiste em remover o atributo auto-increment do campo e simplesmente adicioná-lo novamente. Durante esta operação o MySQL realiza um auto-reset atribuindo o valor correto de acordo com os dados existentes na tabela.

No meu caso o atributo auto-increment já tinha sido removido em outra operação, então foi só executar o segundo comando mesmo para adicionar o auto-increment de volta a coluna id.

Caso você queira simplesmente resetar a sequência auto-increment utilizando os comandos mais tradicionais você poderia utilizar, por exemplo, os comandos abaixo.

SELECT MAX(id)+1 INTO @next_id FROM `mytable`;

ALTER TABLE `mytable` AUTO_INCREMENT = @next_id;

Prontinho… Case Closed!

MySQL Restaurar um Arquivo de Backup exportado pelo MySQLDump

mysql -u <my-user> -p <dbname-wanted-to-restore> < file-data-dump.sql
(password will be asked later)

Esse aqui parece simples, só que é muito fácil de esquecer quando não se usa com frequência.

Acontece que o comando para realizar a exportação de dados do MySQL é bem intuitivo, se chama mysqldump.

Só que para restaurar não tem um mysqlrestore não, o que se usa é o mesmo comando local mysql client. E é um saco ter que lembrar disso ou então ter que pesquisar nos longos sites tutoriais ou manuais técnicos.

Agora taí… mysqldump para exportar e mysql para restaurar.

PHP strtok Recortando Strings Delimitadas por Caracter

$email = 'user.name@mocked.mail';
$user = strtok($email,'@');
var_dump($user); //user.name

$domain = strtok('');
var_dump($domain); //mocked.mail

Há algum tempo atrás trabalhei em um projeto que lidava com importação de dados e a sanitização era um processo imprescindível. Então me deparei com um comando muito curioso que eu não conhecia até então, o strtok.

Na sanitização de email é bastante factível subdividir a string principal em usuário e domínio, então ao invés de recorrer ao tradicional explode eu parti em busca de um novo recurso, algo mais prático.

Apliquei este comando especialmente em testes unitários combinados com o recurso DataProvider.

Veja como é simples conseguir o primeiro nome e sobrenome em dois hits apenas.

$email = 'first-name.last-name@mocked.mail';
$first = strtok(strtok($email,'@'),'.');
var_dump($first); //first-name

$last = strtok('');
var_dump($last); //last-name

Entenda como strtok realmente funciona. Ao informar o caracter delimitador a tokenização é buferizada e o primeiro elemento é disponibilizado e o restante da string permanece no buffer, mas sem ter sido particionada.

$csv = 'column1;column2;column3;column4;column5';
$first = strtok($csv, ';');
var_dump($first); //column1

$remainder = strtok('');
var_dump($remainder); //column2;column3;column4;column5

Para alcançar todos os elementos na cadeia é necessário ir particionando o conteúdo restante que se encontra no buffer, para isto basta informar apenas o delimitador na tokenização. Observe o código abaixo que demonstra um loop até que o retorno seja (bool)FALSE indicando que não existem mais elementos no buffer;

$csv = 'column1;column2;column3;column4;column5';
$token = strtok($csv, ';');

while ($token !== false) {
  echo $token."\n";
  $token = strtok(';');
}

Observe também que você pode utilizar múltiplos delimitadores no processamento e não há uma ordem que precise ser respeitada. A cada ciclo, ao encontrar qualquer um dos caracteres delimitadores o primeiro elemento é imediatamente retornado e o restante permanece no buffer até que ocorra o exaurimento completo do buffer.

$csv = 'column1;column2-column3|column4/column5';
$token = strtok($csv, '|-/;');

while ($token !== false) {
  echo $token."\n";
  $token = strtok('-|;/');
}

Agora você já sabe, precisou quebrar uma string?

Vai de strtok!

SHELL wget Download de Arquivo via Linha de Comando

# baixar com o nome padrão phpunit-9.phar
wget https://phar.phpunit.de/phpunit-9.phar

# baixar e renomear para o nome phpunit
wget -O phpunit https://phar.phpunit.de/phpunit-9.phar

# qualquer endereço http pode ser o alvo para download
wget -O my-project https://mega.nz/file/<mega-nz-download-hash-with-password-embedded>

Parece básico, mas fazer o download de arquivos da internet sem usar um navegador pode ser uma tarefa árdua e desconhecida para a maioria dos usuários da internet.

Porém para desenvolvedores web, engenheiros de software e profissionais de tecnologia da informação dominar essa habilidade deve ser primordial.

O pacote wget é extremamente simples e versátil, pelo menos o seu uso básico não apresenta nenhuma dificuldade como podemos evidenciar acima. Para ambientes Linux ele já vem previamente instalado, ou se necessário pode ser facilmente instalado pelos gerenciadores de pacote.

sudo apt install wget -y      [On Debian, Ubuntu and Mint]
sudo yum install wget -y      [On RHEL/CentOS/Fedora]
sudo emerge -a net-misc/wget  [On Gentoo Linux]
sudo pacman -Sy wget          [On Arch Linux]
sudo zypper install wget      [On OpenSUSE] 

Para usuários MacOS o recurso pode ser instalado pelo gerenciador de pacotes brew.

brew install wget

Ou então, se o seu caso de uso é realmente básico você pode optar pelo uso do CURL, que vai funcionar mesmo no OSX nativamente.

# baixar com o nome padrão phpunit-9.phar
curl -O https://phar.phpunit.de/phpunit-9.phar

# baixar e renomear para o nome phpunit
curl https://phar.phpunit.de/phpunit-9.phar -o phpunit

O wget possui muitas outras funcionalidades mais avançadas, mas a ideia aqui é demonstrar o caso de uso simples mesmo.

Agora você já sabe, baixaki nunca mais!

SHELL Copiando e Colando no Terminal com pbcopy e pbpaste

# copiar conteúdo do arquivo para a memória clipboard
cat linefeed.sql | pbcopy

# colar conteúdo da memória clipboard no terminal
pbpaste

Para quem usa a interface SHELL é bastante corriqueiro tratar e sanitizar dados utilizando uma sequência de comandos e no final ecoar o resultado no próprio terminal.

Mas e daí? Como fazer para transferir estes dados para outro aplicativo?

O mais usual é selecionar os dados como próprio mouse no terminal caracter e pressionar Ctrl+C e posteriormente Ctrl+V no aplicativo destino.

Mas essa operação pode ser cansativa ou mesmo inviável quando estamos falando de um grande volume de dados.

Mas so seus problemas acabaram, agora com pbcopy e pbpaste você não vai mais cometer erros.

Só que estes comandos são originários do mundo OSX. Quem usa ambiente Linux precisa usar o comando xsel ou então simular os comandos Mac via alias.

alias pbcopy=’xsel — clipboard — input’
alias pbpaste=’xsel — clipboard — output’

Pronto, agora você pode usar os mesmos comandos do Mac no seu ambiente Linux.

A propósito, depois de muito pesquisar entendi que o prefixo pb remete a Pasteboard Buffer. É o mesmo que conhecemos no mundo Windows por Clipboard.

Fez sentido agora? Pra mim também…