Skip to content

Instantly share code, notes, and snippets.

@Tomcat-42
Last active January 18, 2020 03:23
Show Gist options
  • Save Tomcat-42/4a83c5f9d113ae294188c6a935bd6f61 to your computer and use it in GitHub Desktop.
Save Tomcat-42/4a83c5f9d113ae294188c6a935bd6f61 to your computer and use it in GitHub Desktop.

.gitignore

Um arquivo com o nome de .gitignore dentro da raiz do repo fará que o git ignore todos os arquivos dentro dele.

Repos

iniciar um repo

$*git init*

clonar um repo

$*git clone [URL]*

Checar o status

$*git status*

Adicionar um arquivo na stage area

$*git add [FILE]*

Checa o que mudou e não foi pra stage area ainda

$*git diff*

Checa o que mudou e já foi pra stage area

$*git diff (--cached|--staged)*

Commits

Fazer um commit nas mudanças já feitas

$*git commit -m [MENSAGEM]*

Adicionando todas as mudanças na stage area autmoaticamente

$*git commit -a -m [MENSAGEM]*

Remover e mover um arquivo

  • Remover da stage area e do disco -> $*git rm [FILE]*
  • Remover apenas da stage area -> $*git rm --cached [FILE]*
  • Mover(Renomer) um arquivo -> $*git rm --cached [FILE]*

Ver o log de commits

$*git log*

Refazer o último commit

$*git commit --amend*

Descartar as alterações em um arquivo(volta pra como estava no ultimo commit)

$*git restore [FILE]*

Remotes

Mostrar os remotes

$*git remote -v*

Adicionar um remote

$*git remote add [NOME] [URL]*

Baixar arquivos de um remote

$*git fetch [REMOTE_NAME]*
  • OBS: $git pull = $git fetch + $git merge

Upar as modificações

$*git push [REMOTE_NAME] [BRANCH]*

Inspecionar um remote

$*git remote show [REMOTE_NAME]*

Remover/Mover um remote

  • Remover -> $git remote remove [REMOTE_NAME]```

  • Renomear -> $*git remote rename [REMOTE_NAME] [NEW_NAME]*

Tags

Listar todas as tags

$*git tag*

Criar uma tag

  • Annotaded tags
$*git tag -a [TAG_NAME] -m [MENSAGEM] [COMMIT_HASH]*
  • Signed tags(GPG)
$*git tag -s [TAG_NAME] -m [MENSAGEM] [COMMIT_HASH]*
  • Lightweight tags
$*git tag [TAG_NAME] [COMMIT_HASH]*

Mostar as informações sobre o commit de uma tag

$*git show [TAG_NAME]*

Verificar uma tag assinada

$*git tag -v [TAG_NAME]*

Upar as tags para o remote

  • Somente uma tag
$*git push [TAG_NAME]*
  • Todas as tags
$*git push --tags*

Branching

Listar todas as branchs

$*git branch -v*

Criar uma nova branch

$*git branch [BRANCH_NAME]*

Deletar uma branch

$*git branch -d [BRANCH_NAME]*

Mudar para uma branch

$*git checkout [BRANCH_NAME]*
  • OBS: $*git checkout -b [BRANCH_NAME]* cria e muda para a nova branch

Merging

$*git merge [BRANCH]*

Resolver um merge conflict

$*git mergetool [FILE]*

Listar as branches que foram/não foram mescladas na branch atual

$*git branch --merged/--no-merged*

Remote branches

Pushing

$*git push [REMOTE] [LOCAL_BRANCH]:[REMOTE_BRANCH]*

Tracking

$*git checkout -b(--track) [LOCAL_BRANCH] [REMOTE_BRANCH]*

Deleting

$*git push --delete [REMOTE] [BRANCH]*

Rebasing

O rebase deixa a história de commits mais linear

Simple rebase

$*git rebase [MASTER_BRANCH] [TOPIC_BRANCH]*
$*git checkout [MASTER_BRANCH]*
$*git merge [TOPIC_BRANCH]*

Rebase a topic branch of another topic branch

$*git rebase --onto [MASTER_BRANCH] [TOPIC_BRANCH]*
$*git checkout [MASTER_BRANCH]*
$*git merge [TOPIC_BRANCH]*

REGRA DE OURO DO REBASE: :Não dar rebase em commits que já foram publicados

Git on the server

Protocolos

  • File

Os arquivos no server são acessados como arquivos na mesma máquina, como pastas compartilhadas ou arquivos dentro do computador.Ambas as operações de R/W são suportadas.\

Acesso -> file://[PROJECT_PATH]\

  • SSH

Os arquivos remotos são acessados via ssh.Contanto que o cliente tenha as credenciais de acesso, ambas as operações de R/W são suportadas nesse protocolo.\

Acesso -> ssh://[USER]@[SERVER]:[PROJECT_PATH].git

  • Git

Daemon especial que escuta na porta 9418 que permite uma funcionalidade parecida com o ssh mas sem nenhuma autenticação.Como esse protocolo não possui nenhuma autenticação, qualquer um pode ler/escrever no servidor se essas opções forem ativadas.\

Para um repositório remoto funcionar com esse protocolo deve ser criado o arquivo git-export-daemon-ok\

Acesso -> git://[SERVER]/[PROJECT_PATH].git

  • http/s

Os arquivos são acessados a partir de um servidor http, como o apache ou o nginx.Somente a operação de Leitura é suportada out of the box, as operações de escrita requerem a configuração de um servidor webDAV.\

Para o servidor servir corretamente os arquivos do git, é necessário usar um post receive hook: mv hooks/post-update.sample hooks/post-update.\

Acesso -> http://[SERVER]/[PROJECT_PATH].git

Configurar o servidor

Basicamente o servidor deve conter o repositório bare e ser acessível via ssh para os usuários:

  • Importar um repositório
$*git clone --bare [REPO] [REPO].git*
  • Criar um novo repositório

$git init --bare

Após isso, copiar o repositório bare para o servidor, por exemplo, usando o scp:

$*scp [REPO].git [USER]@[SERVER]:[DIR]*

Obs: Caso haja algum problema com permissões do repositório no servidor, usar o comando $git init --bare --shared.

Acesso via ssh

Para dar acesso à todos no servidor existem duas alternativas:

  • Contas individuais

Criar uma conta no server para cada usuário com o comando $useradd -m [USER] -G [OPTIONAL_GROUPS] e importar suas chaves públicas no diretório ~/.ssh de cada usuário.

  • Conta única

Criar uma conta no server(e.g. git) e importar as chaves públicas de todos os usuário para o diretório ~/.ssh dessa nova conta. Uma precaução adicional é mudar o shell de login da nova conta no arquivo /etc/passwd para /usr/bin/git-shell, assim a nova conta só poderá usar o sshd para interagir com o git, não podendo logar com um shell real na máquina.

Http/s

Para ser possível a leitura do repositório deve-se configurar uma entrada de VirtualHost no servidor http e o hook de post-update disponível na pasta .git/hooks/post-update.sample.\ Tutorial

  • gitweb

O gitweb é uma visualização web do repositório git.Para ver uma visualização $*git instaweb --http=[SERVER]* , e para rodá-lo permanentemente é só adicionar o script CGI em uma entrada de VirtualHost do apache ou outro webserver.

Gitosis

O gitosis é um gerenciador de acesso e de chaves públicas para os projetos git no servidor.\ info

Git Daemon

O git daemon é uma alternativa ao http/s para o acesso público à um repositório. Para rodá-lo adicionar um script no gerenciador de daemons do sistema, como o systemd ou o sysv.

Contributing to a project

Commits Guidelines

  • Checar por espaços em branco antes de commitar
*$git diff --check*
  • Organizar os commits de modo a cada um mostrar uma mudança significativa e diferente

  • As mensagens de commit devem ter uma breve introdução de no máximo 50 caracteres, seguida de uma explicação mais detalhada de no máximo 70 caracteres.

  • As mesagens de commit devem ser escritas no imperativo(e.g. "Fix Bug Y", "Fix Issue X")

  • Tópicos com asteriscos ou hífens são uma boa idéia

Simple Private Workflow

Todos os desenvolvedores tem permissão de leitura/escrita no repositório, assim, todos realizam suas modificações e sincronizam com o servidor:

start:
	fetch remote changes
	merge changes(if any)
	Do work
	fetch remote changes
	merge changes(if any)
	Push to remote
	start

Private Managed Team

Nesse tipo de workflow diferentes times trabalham em partes diferentes do projeto e a integração dessas mudanças são feitas por um time diferente. Por exemplo o repositório pode ter a branch master read-only para todos os desenvolvedores, menos aqueles do time de integração, assim os times criam branches tópicos e fazem upload delas para ser integrada pelo time de integração.

Public Small Project

Nesse tipo de projeto os contribuidores não tem acesso de escrita algum no servidor. Dessa forma, os contribuidores devem criar um fork, realizar suas contribuições e então fazer um pull request para que suas modificações sejam integradas no projeto principal:

*$git clone [PROJECT_URL]*
*$cd [PROJECT_DIR] ; git checkout -b [TOPIC_BRANCH]*
... do work...
*$git remote add [FORK_NAME] [FORK_URL]*
*$git push --set-upstream [FORK_URL] [TOPIC_BRANCH]*
*$git request-pull origin/master [FORK_URL] #Gera uma saída que pode ser enviada por email para o desenvolvedor*

Email patches

Para gerar arquivos de patch dos commits de uma branch para serem aplicados em outra(master):

*$git checkout -b [NEW_BRANCH]*
... do work and commit ...
*$git format-patch -M [BRANCH_ALVO]*

Cada commit gerará um arquivo de patch, que pode ser enviado por smtp:

*$git send-email *.patch*
  • OBS: Uma alternativa à montar seu próprio servidor smtp em uma vps é utilizar o serviço de smtp do gmail. Para habilitá-lo é preciso ativar o acesso de apps potencialmente não seguros na conta do google e configurar as credenciais de smtp nas configurações do gmail, e adicionar algo parecido com isso no arquivo ~/.gitconfig:
[sendemail]
	from= Pablo <pablohuggem@gmail.com>
  	smtpencryption = tls
  	smtpserver = smtp.gmail.com
  	smtpuser = pablohuggem@gmail.com
  	smtpserverport = 587
	confirm = auto

Maintaining a Project

Topic Branches e namespaces

Geralmente é uma boa idéia criar uma branch para aplicar e testar novas contribuições. Outra boa convenção é utilizar algum tipo de namespace para testar as contribuições do projeto, por exemplo, criar a branch foo/bar para testar a feature bar criada por foo

Apllying patches

Em projetos open source uma maneira de receber contribuições são patches enviados por email.

  • Com o apply:

*$git apply [PATCH]*

Obs:A flag --check checa se a aplicação acontecerá sem conflitos.

O git apply deve ser usado para aplicar patches gerados com o utilitário diff. Entretanto, usar esse formato de patch não é recomendado.

  • Com o am:

*$git am [PATCH]*

A flag -3 faz um three way merge ao aplicar o patch, assim se ocorrer algum conflito é possível resolvê-lo com o ´´´*$git mergetool*A flag-iaplica os patches no modo interativo. Por exemplo$git am -i [DIR]``` aplicará todos os patches em [DIR] interativamente.

  • com o patch

Aplicar o patch:

$patch -p1 < [PATCH]

Remover o patch:

$patch -p1 -R < [PATCH]

Checking out remote branches

Outra maneira de receber contribuições é o endereço de um repositório fork onde as modificações sobre o projeto original estão. Dessa forma, tendo o endereço do repositório é possivel baixa-lo:

*$git remote add [NAME] [URL]*
*$git fetch [NAME]*

Por fim, pode ser criarda branches locais que seguirão as branchs remotas do repositório:

*$git branch -b(--track) [LOCAL_BRANCH] [REMOTE]/[REMOTE_BRANCH]*

Determining What Is Introduced

É útil visualizar os commits em uma branch que estão frente da branch master:

$git log [BRANCH] --not master

Para visualizar as diferenças entre os arquivos de duas branches ou commits:

$git diff [OBJECT] [OBJ]

Por fim, para visualizar as diferenças entre o último commit de uma branch e seu ancestral comum à outra branch utliza-se a sintaxe dos 3 pontos:

$git diff [OBJECT]...[OBJECT]

Integrating Contributed Work

  • Merging workflows

Um workflow simples é sempre mesclar novas branches-tópicos diretamente na branch master do projeto. Porém, em projetos que requerem uma maior estabilidade é recomendado a utilização de uma branch de integração (e.g. develop), onde todo o trabalho de branches tópicos são mesclados, e assim que essa branch esteja estável é mesclada na master.

  • Rebasing and cherry-picking workflows

A fim de manter uma história mais linear, pode-se aplicar o trabalho de uma branch-tópico em outra branch mais estável com o $git rebase`[BRANCH_ESTÁVEL] Uma outra alternativa é utilizar o $git cherry-pick [SHA-1] para aplicar somente o trabalho de um commit na branch atual.

Tagging releases

  • Gerar uma tag assinada
$git tag -s [VERSION] -m [MENSAGEM]
  • Distribuir uma chave pública GPG no projeto

Depois de assinar uma tag é necessário distribuir a chave pública do GPG para ser possível para todos verificar suas tags. Uma maneira de fazer isso é exportar a chave pública como um objeto do git, e colocar uma tag nele:

  • Listar suas chaves: ```$gpg --list-keys``

  • criar um objeto com tag da chave


- importar a chave que está no objeto no chaveiro do gpg
```$git show [TAG_NAME] | gpg --import```

### Generating a Build Number

Para gerar um número de versão baseado na última tag, número de commits desde a última tag e no checksum do último commit:

$git describe [BRANCH]


para gerar uma tag parcial entre duas versões pode ser utilizado

$git tag -s $(git describe [BRANCH]) -m [MENSAGEM]

### Preparing a Release

Para gerar um snapshot de uma release e compactá-la com o tar e gunzip:

$git archive [BRANCH] --prefix=[ROOT_NAME] | gzip > [NAME].tar.gz

Gerar no formato zip:

$git archive [BRANCH] --prefix=[ROOT_NAME] --format=zip > [NAME].zip


uma dica é utilizar o ```$git describe [BRANCH]``` para criar os nomes dos snapshots:

$git archive [BRANCH] --prefix=[ROOT_NAME] | gzip &gt; $(git describe [OBJECT]).tar.gz


### Shortlog

Para resumir todos os commits do projeto para possivelmente mandar por email:

$git shortlog --no-merges [BRANCH]


## Github

### Workflow em projetos open source


   1 Fork the project

   2 Create a topic branch from master.

   3 Make some commits to improve the project.

   4 Push this branch to your GitHub project.

   5 Open a Pull Request on GitHub.

   6  Discuss, and optionally continue committing.

   7 The project owner merges or closes the Pull Request.

   8 Sync the updated master back to your fork.

### References

Para referenciar um pull request ou uma issue adicionar ```#[NUM]```, onde [NUM] é a ID da issue ou do pull request. Para referenciar uma issue/pr de um usuário específico ```[USENAME]#[NUM]```, e para referenciar uma issue/pr de outro repo ```[USERNAME]/[REPO]#[NUM]```.
   É possível referenciar um commit, para isso é preciso adicionar todos os caracteres do checksum dele.

### Github flavoured Markdown

Todo comentário ou mensagem pode ser escrito em markdown no github. Algumas peculiaridades:

* Tasks list:

Ex:

```markdown
- [X] Tarefa 0
- [ ] Tarefa 1
- [ ] Tarefa 2
  • Code snippets

Para adicionar um bloco de código é começar e terminar ele com três `. Para obter sintax highlighting é só colocar a linguagem depois dos três primeiros `. Ex:

import foo
for i in list
	print(i)
  • Quoting

Para adicionar uma quote é só preceder a linha com um >. Ex:

Foo Bar

  • Emojis(????)

Um emoji é adiconado com :[NAME]:. Ex:

Grande dia 👍 🇧🇷 👌

  • Images

Para adicionar uma imagem : ![NAME](URL)

Keep you repositoriy up-to-date

Para facilitar o ciclo de fetch-merge-push para manter o fork atualizado em relação ao upstream é recomendado adicionar o repo upstream como remote, adicionar a branch remota como upstream da branch local e adicionar o seu repositório(origin) como padrão de push:

$git remote add [REMOTE_NAME] [REMOTE_URL]
$git branch --set-upstream-to=[REMOTE_NAME]/[BRANCH] [LOCAL_BRANCH]
$git config -local remote.pushDefault origin

assim os comandos do ciclo ficam simplificados à:

$git checkout master
$git pull
git push

Pull requests refs

Todos os pull requests no github são armazenados como referencias no repositório. Para lista-los: $git ls-remote [REMOTE]. Existem duas referências para cada pull request: as que terminam com /head apontam para o último commit na branch do pull request. Dessa forma, para baixar a "branch" do pull resquest do servidor:

$git fetch origin refs/pull/[NUM]/head

A "branch" será salvo como 'FETCH_HEAD', assim, para mescar todo o trabalho do pull request: $git merge FETCH_HEAD

Para automaticamente baixar todos os pull requests como branches, adiconar essa linha na seção do remote origin no arquivo .git/config:

fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

Mentions and notifications

Para mencionar um usuário, preceder seu username com um @. Quando um usuário é mencionado ele receberá uma notificação.h

Special files

  • README

O arquivo README serve para reunir todas as informações úteis para o projeto ou pertinentes de alguma forma. O github reconhece qualquer formato de README (README.md, README.txt, ...).

  • CONTRIBUTING

O arquivo CONTRIBUTING serve para definir as diretrizes utilizadas para a contribuição no projeto. Esse arquivo pode ser de diferentes formatos.

github api

A api do gitub é muito poderosa, é possivel automatizar qualquer ação do site. Para criar um token de acesso da api é so ir nas configurações da conta. A biblioteca ocktokit - como muitas outras - pode ser usada como uma abstração para a API do github. Mais informações sobre a API.

Git tools

Revision selection

  • Short SHA-1

Para referenciar um commit ou uma branch é possível usar alguns dos primeiros caracteres do seu checksum, e não necessariamente todos os 40 caracteres.

Obs: A flag --abbrev-commit do comando git log mostra uma versão abreviada dos commits.

  • Branch references

Para referenciar o commit no "topo" de uma branch pode-se passar somente o nome da branch.

Obs:O comando $git rev-parse [BRANCH] Mostra o SHA-1 específico do último commit de uma bracnh.

  • Git reflog

O git armazena um log de todas as operações realizadas no repositório local. Para visualizar esse histórico:

$git reflog

É possível ver uma entrada específica de uma branch específica do reflog :

$git reflog BRANCH@{NUM}

Também, é possível ver entradas que aconteceram à algum tempo atràs

$git reflog BRANCH@{yesterday}
$git reflog BRANCH@{2.months.ago}
  • Ancestry references

Se for colocado um '^[n]' antes da referência de um objeto, o git mostra o n-ésimo objeto pai dele:

$git show HEAD^

Também é possível usar a sintaxe '~[n]' ques mostra o n-ésimo primerio objeto pai dele.

  • Commit ranges: double dot

A sintaxe de dois pontos(..) é usada para mostras todos os commits que podem ser alcançados de uma branch mas não da outra:

git show [BRANCH_0]..[BRANCH_1] mostra os commits que são alcançaveis pela branch 1 e não pela branch 0

git show [BRANCH_1]..[BRANCH_0] mostra os commits que são alcançaveis pela branch 0 e não pela branch 1

  • Commit ranges: Various Branches

Para imprimir os commits alcançáveis de diversas branches:

$git log [REF_A] [REF_B] [REF_C]

Para mostrar os commits alcançáveis por [REF_A] e [REF_B] mas não por [REF_C]:

$git log [REF_A] [REF_B] --not [REF_C]
  • Commit ranges: triple dot

Para referenciar todos os commits que são alcançáveis por uma ref xor outra:

$git log [REF_A]...[REF_B] --left-right

Obs:A flag --left-right mostra de que lado é cada commit na saída

Interactive Staging

Para abrir um shell interativo da staging area:

$git add -i(--interactive)

Stashing and cleaning

A stash do git é uma pilha que guarda as modificações na branch atual para serem reaplicadas depois, assim é possível guardar um trabalho feito pela metade em uma branch e trocar para outra.

  • Colocar as modificações na pilha
$git stash push
  • Tirar as modificações da pilha
$git stash pop
  • Listar as modificações dapilha
$git stash list
  • Aplicar a NUM-ésima modificação da pilha
$git stash apply stash@{NUM}
  • Adicionar somente algumas modificações na stash
$git stash push --patch
  • Criar uma branch da stash
$git stash branch [BRANCH_NAME]
  • Limpar o diretório

Para deletar todos os arquivos e diretórios não adicionados ao git:

$git clean -fd

Uma versão mais segura para o comando acima é colocar os arquivos na stash:

$git stash --all

A flag --dry-run(-n) testa quais arquivos vão ser deletados

A flag ``-xdeleta também arquivos especificados no arquivo.gitignore```

Para rodar o git clean no modo interativo:

$git clean -i

Signing your work

  • Listar as chaves públicas/privadas gpg:
$gpg --list-keys / $gpg --list-secret-keys 
  • Gerar um par de chaves gpg:
$gpg --full-gen-key
  • Adicionar uma chave no git
$git config --globar user.signinkey SHA-1
  • Para assinar uma tag adicionar a flag -s

  • Para verificar uma tag assinara adicionar a tag -v. Para issoé necessário ter a cheve de quem assinou no chaveiro do gpg.

  • Para assinar um commit:

$git commit -S
  • Para assinar um commit resultante de um merge:
$git merge -S [BRANCH]
  • Os comandos $git pull e $git merge irão aceitar somentes commits assinados se for passada a flag --verify-signatures

OBS: É importante que todos no time entendam como lidar com o gpg no git se for decidido adicionar assinaturas de tags e commits no workflow.

Searching

  • Git Grep

O comando git grep procura por uma string ou expressão regular na base de dados.

$git grep -p -n [STRING]

A flag -n(--line-number) mostra a linha da ocorrência no arquivo

A flag -p(--show-function) mostra um trecho do código que da ocorrência

A flag -c(--count) Resume a saída com somente o arquivo e a linha da ocorrência

A flag --and permite que uma combinação de strings sejam levadas em consideração na busca

  • Git log searching

Para procurar os commits em que uma string foi modificada:

$git log -S [STRING]

Para mostrar o histórico de uma função:

$git log -L :[STRING]:[FILE]

Rewriting story

É recomendado que somente se reescreva os commits que não foram publicados.

  • Mudar o último commit:
$git commit --amend

Obs: A flag --no-edit não mudará a mensagem de commit.

  • Changing Multiple commit messages

O rebase interativo pode ser usado para mudar a mensagem de commits antigos. Para mudar a mensagem de até o NUM-ésimo commit ancestral da HEAD:

$git rebase -i HEAD~[NUM]
  • Reordering/deleting commits

Reordenar e deletar commits também pode ser feito com o rebase interativo:

$git rebase -i HEAD~[NUM]
  • Squashing commits:

Para condensar vários commits em um só, pode ser usado o rebase interativo, e modificado o arquivo para algo como isso:

pick ae125f9 [MENSAGEM]
squash 45feaf7 [MENSAGEM]
...Vários commits...
squash 83eadfe [MENSAGEM]
  • splitting a commit

Para dividir um commit em vários pode-se utilizar o rebase interativo:

$git rebase -i HEAD~[NUM]

E mudar o commit que vai ser dividido para algo como isso:

pick ae125f9 [MENSAGEM]
edit 45feaf7 [MENSAGEM]
pick 83eadfe [MENSAGEM]

Por fim desfazer as alterações e refazer os commits:

$git reset HEAD^
git add [SOME_FILE]
git commit -m [SOME_MESSAGE]
git add [OTHER_FILE]
git commit -m [OTHER_MESSAGE]
git rebase --continue
  • Filter branch

O filter branch é usado para substituir as informações de commits de uma maneira automatizada

Para apagar um arquivo de todos os commits:

$git filter-branch --tree-filter 'rm -f [FILE]' HEAD

Para tornar um subdiretório a nova raiz do projeto:

$git filter-branch --subdirectory-filter trunk HEAD

Para mudar o email em todos os commits, pode ser usado um script como esse:

$git filter-branch --commit-filter '
	if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
	then
		GIT_AUTHOR_NAME="Scott Chacon";
		GIT_AUTHOR_EMAIL="schacon@example.com";
		git commit-tree "$@";
	else
		git commit-tree "$@";
		fi' HEAD

Reset

O gut manipula três árvores na sua operação:

  • HEAD

O HEAD é o snapshot do último commit na branch atual.

O comando $git cat-file -p HEAD mostra mais informações sobre essa árvore.

  • Index(staging área)

O index é basicamenteas mudanças propostas para o novo commit

O comando $git ls-files -s mostra todos os arquivos no index.

  • Working directory

São os arquivos que de fato estão no diretório.

  • Modificando o HEAD

Assim, o comando $git reset --soft [OBJ] move o ponteiro da branch atual($git checkout move o ponterio HEAD para uma branch) sem modificar o Index ou o Working Directory.

  • Modificando o Index

Para modificar também o Index, a flag --mixed é usada:

$git reset --mided [OBJ]
  • Modificando o Working Directory:

Para modificar também os arquivos no diretório atual, usa-se a flag --hard:

$git reset --hard [OBJ]
  • Modificar o conteúdo de somente alguns arquivos

Caso o caminho de algum arquivo seja passado como parâmetro para o reset ele restaurará esse arquivo para a versão contidda no Objeto também passado como parâmetro:

$git reset [OBJ] [FILE]
  • Squashing commits with reset

O reset pode mer usado para juntar diversos commits em um só:

$git reset --soft HEAD~[NUM_COMMITS]
$git commit -m [MESSAGE]

Advanced Merging

Ignoring whitespaces

Para ignorar diferenças de espaços em branco em merges, a flag --Xignore-space-change

Mostrar as versões do arquivo em um commit

Para mostrar as diferentes versões do arquivo("topos" das branches e ancestral comum):

$git show :1:[FILE1] > NEW_FILE1 #Ancestral comum
$git show :2:[FILE1] > NEW_FILE2 #Topo da branch atual
$git show :3:[FILE1] > NEW_FILE3 #Topo da branch a ser mesclada

O comando $git ls-files -u mostrará os checksums dos 3 estágios de cada arquivo.

Mostrar as diferenças

Para mostrar as diferenças entre os arquivos das branches e do ancestral comum com o resultado do merge:

$git diff --ours #branch atual 
$git diff --theirs #branch mesclada
$git diff --base #ancestral comum

Checking out conflicts

Para mostrar o conflito no arquivo de forma diferente(incluir o ancestral comum):

$git checkout --conflict=diff3 [FILE]

Ou para escolher um lado do arquivo:

$git checkout --ours|--theirs [FILE]

Merge log

Para mostrar todos os commits entre o HEAD, o MERGE_HEAD e o ancestral comum:

$git log --oneline --left-right HEAD...MERGE_HEAD

Para mostrar somente os commits que modificaram algum arquivo em conflito

$git log --oneline --left-right --merge 

Combined Diff

Após um merge conflict, o commando $git diff mostra as diferenças entre a versão do arquivo no ancestral comum, na branch a ser mesclada e na branch atual. O mesmo acontece com $git log --cc -p.

Undoing merges

Existem duas formas de reverter um merge:

  • Fix the references:

Se o merge só ocorreu localmente, a maneira mais fácil de revertê-lo é:

$git reset --hard HEAD~
  • Revert

Nessa maneira, o git fará um novo commit que reverterá as modificações anteriores

$git revert -m 1 HEAD

Other types of merges

  • Ours or Theirs preference

Para favorecer a versão dos arquivos da branch atual ou da branch que será mesclada em um merge, usa-se as flags -Xours ou -Xtheirs :

$git merge -Xours [FILE] #Favorece a versão do arquivo na branch atual

Para fazer com que o git nem olhe para um dos lados no merge(Porém o novo commit ainda continuará tendo ambos os commits das branchs como pai):

$git merge -s ours/theirs [BRANCH]

Rerere

A ferramenta do git rerere - acrônimo para *resuse recorded resolution - usa resoluções de conflitos anteriores em novos conflitos, basicamente um cache de resoluções de conflitos. Para ativar essa funcionalidade:

$git config --global rerere.enabled true

Debugging with Git

File annotation

Para determinar o commit em que uma certa linha foi modificado em algum arquivo:

$git blame -L [Start],[END] [FILE]

A flag -C Mostra se uma linha de código foi copiada de um arquivo em um commit específico, se sim mostra quais..

$git blame -C -L [Start],[END] [FILE]

Binary Search

O comando bisect faz uma busca binária na história de commits para ajudar a identificar o commit específico onde um bug foi inserido.

Para começar a busca:

$git bisect start

Como sabemos que o HEAD está bugado:

$git bisect bad

Após isso, marcar o último commit que não estava bugado:

$git bisect good [SHA1]

Dessa forma, o git irá fazer uma busca binária nos commits entre o commit atual bugado e o último commit que estava bom. O usuário irá testar cada um desses commits, e marcá-los:

$git bisect good #se esse commit funciona
$git bisect bad #se esse commit não funciona

Quando o commit que introduziu o bug foi encontrado, é necessário resetar o HEAD:

$git bisect reset

O bisect pode ser totalmente automatizado se for criado um script booleano(0 bom, !0 ruim) para testar o código:

$git bisect start HEAD [VERSÃO_BOA]
$git bisect run [SCRIPT]

Submodules

Para adicionar um submódulo ao projeto:

$git submodule add [URL]

Para listar os submodulos com o diff:

$git diff --cached --submodule

Para clonar um projeto com submódulos:

$git clone [MAIN_PROJECT]
$git submodule init
$git submodule update

Uma maneira mais fácil:

$git clone --recurse-submodules [MAIN_PROJECT]
  • Atualizando os submódulos

A maneira mais comum de se trabalhar com submódulos é somente consumi-los sem modificar nada. Nesse caso, para atualizar o submódulo é necessário utilizar somente o $git merge. Também pode-se usar o comando $git submodules update --remote --merge/--rebase para atualizar automaticamente os submódulos.

Para receber um sumário das modificações nos submódulos no status:

$git config (--global) status.submodulesummary true
  • Upando o trabalho

Para upar as modificações do repositório incluindo aquelas dos submódulos, usa-se a flag --recurse-submodules=check/on-demand do push. A opção check vai fazer o push falhar se nenhuma mudança no submódulo foi commitada. A opção on-demand tentará upar os commits de cada submódulo antes de upar os do módulo principal:

$git push --recurse-submodules=check

Para fazer uma opção padrão:

$git config (--global) push.recurseSubmodules check/on-demand
  • Dicas

O comando $git submodules for each '[COMANDO]' executa um comando do git em cada submódulo. Por exemplo, para empilhar as modificações de todos os submódulos na pilha do git:

$git submodule foreach 'git stash'

Para produzir um diff geral de todos os submódulos:

$git diff; git submodule foreach 'git diff'
  • Aliases úteis
$git config --global alias.subdiff '!'"git diff && git submodule foreach 'git diff'"
$git config --global alias.subpush 'push --recurse-submodules=on-demand'
$git config --global alias.subupdate 'submodule update --remote --merge'
  • Problemas com submódulos:

Se for criada uma nova branch, adicionado um submódulo nela, e então trocado para uma branch sem aquele submódulo, a nova branch terá o subdiretório desse submódulo como um diretório não monitorado pelo git. Para remover o subdiretório da branch que não deveria tê-lo:

$git clean --ffdx
$git checkout [BRANCH_SUBMODULO]
$git submodule update --init

Outro problema é criar um submódulo em um subdiretório existente. Para isso, primeiro é necessário excluir o subdiretório do Index, e então adicionar o submódulo:

$git rm -r [SUBDIR]
$git submodule add [URL]

Bundling

O git bundle pode ser usado para juntar modificações de vários commits em um arquivo binário único. Por exemplo, para juntar os commits no intervalo [[START_COMMIT], [END_COMMIT]] da branch [BRANCH]:

$git bundle create [BUNDLE_NAME] [START_COMMIT] [END_COMMIT] -b [BRANCH]

Para aplicar clonar o bundle:

$git clone [BUNDLE_NAME]

Para verificar a integridade do bundle:

$git bundle verify [BUNDLE_NAME]

Credential Storage

O padrão do git é não armazenar nenhuma credencial em memória ou disco.

Para mudar o modo de armazenar as credenciais:

$git config --global credential.helper "cache --timeout=[SECS]"
$git config --global credential.helper "store --file [PATH]"

No linux pode ser utilizado o gerenciador de credenciais do git:

$git config --global credential.helper libsecret

Customizing Git

Configuration files

As opções de configurações são modificadas com o comando $git config [CONFIG] [VALUE]

As configurações a nível de sistema se encontram em /etc/gitconfig

As configurações a nível de usuário se encontram em ~/.gitconfig ou ~/.config/git/config

As configurações a nível de repositório se encontram em .git/config

Basic client configuration

  • core.editor

Muda o editor de texto usado nas operações do git. Por exemplo para mudar o editor para o vim:

$git config --global core.editor vim
  • commit.template

Adiciona um template para todos os commits. Útil para se lembrar de alguma guideline de commits.

$git config --global commit.template [FILE]
  • core.pager

Muda o paginador padrão do git, como o less ou more.

$git config --global core.pager less/more #Setar um paginador
$git config --global core.pager '' #Não usar um paginador
  • user.signinkey

Muda a chave gpg usada nas operações de assinatura no git:

$git config --global user.signinkey [GPG_KEYID]
  • core.excludesfile

Adiciona um template para o arquivo .gitignore dos repositórios:

$git config --global core.excludesfile [PATH]
  • help.autocorrect

Ativa a auto-correção de comandos digitados errado:

$git config --global help.autocorrect [SECS]
  • color.ui

Muda as situações em que o git imprimirá códigos de cores:

$git config --global color.ui auto #imprimirá cores somente na saída para o terminal
$git config --global color.ui false #não imprimirá cores
$git config --global color.ui alwayes #sempre imprimirá cores.Não recomendado
  • color.*

Muda as situações em que cores são impressas em comandos específicos,e.g.:

$git config --global color.branch false
...
  • color.*.meta

Muda as cores impressas em cada comando:

$git config --global color.*.meta "[FOREGROUND] [BACKGROUND] [ATTR]"

[FOREGROUND] = {normal, black, red, green, yellow, blue, magenta, cyan, white} [BACKGROUND] = {normal, black, red, green, yellow, blue, magenta, cyan, white} [ATTR] = {bold, dim, ul, blink, reverse}

  • merge.tool

Ferramente para a resolução de merge conflicts. Por exemplo, para setar o vimdiff como ferramenta de resolução de conflitos:

$git config --global merge.tool vimdiff
  • diff.external

Para setar uma feeramente externa de diff:

$git config --global diff.external [TOOL]
  • core.autocrlf

Auto converte os chars cr-lf usados no windows em novas linhas para somente lf usados no linux:

$git config --global core.autocrlf true/false
$git config --global core.autocrlf input
  • core.whitespace

Existem 6 opções de core.whitespace.*. As três principais já são habilitadas por padrão.

Git Attributes

Os atributos são "configurações" aplicadas à somente alguns arquivos e/ou subdiretórios do projeto. Os atributos são setados no arquivo .gitattributes ou .git/info/attributes.

  • Binary files

É possível usar os atributos para dizer ao git quais arquivos devem ser tratados como binários. Assim, insira algo assim no arquivo .gitattributes:

*.[EXTENSION] binary

Também é possível usar uma ferramenta de diff específica para algum tipo de arquivo, e.g.:

*.docx diff=word

Assim, os arquivo terminados em .docx usarão o filtro word, que pode ser configurado posteriormente com a ferramenta de conversão docx2txt:

$git config diff.word.textconv docx2txt

Imagens com metadados podem usar a ferramenta de diff exiftool:

No arquivo .gitattributes:

*.png diff=exif

Após, setar a configuração:

$git config diff.exif.textconv exiftool
  • Exporting

É possível excluir alguns arquivos/subdiretórios ao gerar um archive. Para isso, adicionar algo parecido no arquivo .gitattributes:

[FILE] export-ignore
  • Merge strategies

Também é possível usar estratégias de merge diferentes para arquivos diferentes no projeto. Para isso, adicionar algo parecido no arquivo .gitattributes:

[FILE1] merge=ours
[FILE2] merge=theirs

Git hooks

Os hooks sõa scripts executados quando certos eventos ocorrem no git, como por exemplo commits, pushes, etc. Os hooks são encontrados em .git/hooks.

Client-Side Hooks

  • pre-commit

Esse hook é executado antes mesmo de ser digitado a mensagem de commit.Um retorno diferente de 0 aborta o commit, porém a flag --no-verify faz o commit mesmo assim.

  • prepare-commit-msm

Esse hook é executado depois da mensagem padrão ser criada mas antes do editor de texto ser chamado para escrever a mensagem de commit.

  • commit-msg

Esse hook é executado depois da mensagem de commit ser escrita.

  • post-commit

Esse hook é executado depois de um commit ser feito

  • applypatch-msg

Executado antes de ser aplicado o patch para checar a mensagem de commit

  • pre-applypatch

Executado depois de aplicar o patch mas antes de ser gerado o commit

  • post-applypatch

Esse hook éexecutado após o commit do patch ser feito

  • pre-rebase

Executado antes de ser realizado o rebase.

  • post-rewrite

Executado após qualquer comando que modifique commits, como $git rebase, $git commit --amend, ... .

  • post-checkout

Executado após checkout bem sucedido

  • post-merge

Executado após um merge bem sucedido.

  • pre-push

Executado antes dos objetos serem transferidos para o remoto.

Server-Side Hooks

  • pre-receive

Executado antes que os objetos recebidos de um cliente sejam processados.

  • update

É análogo ao hook pre-receive, porém é executado para cada branch sendo modificado pelo cliente.

  • post-receive

É executado após todo o porcesso de recebimento de dados.

Outros

Recuperar uma branch

Para recuperar uma branch perdida(um commit que não é referenciado por outro commit), primeiro é necessário saber o checksum do último commit dessa branch. Para isso é usado o reflog e o log:

$git reflog -[NUM_COMMITS]
$git log -g -[NUM_COMMITS]

Por um acaso, se não houver logs, a ferramenta do git fsck pode ser usada para encontrar commits "perdidos" :

$git fsck --full

Agora, pode ser criada uma nova branch que aponta para aquele checksum:

$git branch [BRANCH_NAME] [SHA1]

Deletar arquivos grandes

Primeiro remover o arquivo do Index Atual:

$git rm [FILE]

Pode ser usado o garbage colector$git gc ou o $git count-objects -v --human-readable para ver o quanto de espaço está sendo usado.

Para ver os [N] maiores arquivos entre os packs:

$git verify-pack -v .git/object/pack/pack[X]...[Y].idx | sort -k 3 -n | tail -[N]

Agora, tendo o SHA1 dos maiores blobs, é possível encontrar os nomes dos arquivos associados à eles:

$git rev-list --objects --all | grep [SHA1]

Para ver o primeiro commit em que o arquivo foi modificado::

$git log --oneline --branches -- [FILENAME]

Por fim, é preciso reescrever todos os commits a partir do primeiro em que o arquivo foi modificado para de fato remover o arquivo:

$git filter-branch --index-filter 'git rm --ignore-unmatch --cached [FILENAME]' -- SHA1^..HEAD

O histórico não contém mais nenhuma referência para o objeto, porém os diretórios .git/refs/original/ e .git/logs/ sim. Portanto, para remover essas referências somente é necessário remover os diretórios e rodar o garbage colector:

$rm -rf .git/logs/ .git/refs/original && git gc

O objeto não é referenciado por nada - não será transferido em um push ou fetch - porém ainda existe no repositório local. Para removê-lo da base de dados:

$git prune --expire now

Environmente Variables

  • Global Behavior

GIT_EXEC_PATH: Determina o diretório onde o git procura por seus sub-programas.

HOME: Onde o git procura pelo arquivo de configuração do usuário.

PREFIX: Onde o git procura pelo arquivo de configuração do sistema.

GIT_CONFIG_NOSYSTEM: Se setada, desativa as configurações system-wide.

GIT_PAGER: Controla o programa paginador.

GIT_EDITOR: Controla o editor de texto padrão do git.

  • Repository Locations

GIT_DIR: Localização do diretório .git. Se não for especificada, o git sobe a árvore de diretórios até achar um diretório .git

GIT_CEILING_DIRECTORIES: Controla o comportamento do git em procurar por diretórios .git.

GIT_WORK_TREE: Caminho da raiz do repositório.

GIT_INDEX_FILE: Caminho do arquivo de index.

GIT_OBJECT_DIRECTORY:Caminho do diretório de objetos do git.

GIT_ALTERNATE_OBJECT_DIRECTORIES: Uma lista na forma /dir/1/:/dir/2/...:/dir/n/ que representa diretórios alternativos onde o git procurará por objetos.

  • Pathspecs

GIT_GLOB_PATHSPECS: Se setado para 1 caracteres como * serão interpretados como wildcards(Padrão).

GIT_NOGLOB_PATHSPECS: Se setado para um caracteres como * serão interpretados normalmente.

GIT_LITERAL_PATHSPECS: Se setado não permite nenhum caractere wildcard.

GIT_ICASE_PATHSPECS: Se setado, os caracteres de wildcard funcionarão de maneira não sensiva ao caso.

  • Commiting

GIT_AUTHOR_NAME: Usada para definir o nome do autor dos commits.

GIT_AUTHOR_EMAIL: Usada para definir o email do autor dos commits.

GIT_AUTHOR_DATA: Usada para definir data no campo do autor.

GIT_COMMITER_NAME: Usada para definir o nome do autor do commit.

GIT_COMMITER_EMAIL: Usada para definir o email do autor do commit.

GIT_COMMITER_DATA: Usada para definir data no campo do autor do commit.`

  • Networking

GIT_SSL_NO_VERIFY: Se setada o git nçao verificará certificados ssl.

GIT_HTTP_LOW_SPEED_LIMIT: Se a velocidade de transferência por htttp for menor que essa variável pelo tempo GIT_HTTP_LOW_SPEED_TIME, o git cancelará a operação atual.

GIT_HTTP_USER_AGENT: Seta a string de user agent que o git usa nas operações http.

  • Diffing and merging

GIT_DIFF_OPTS: Seta o número de linhas mastradas pelo comando git diff.

GIT_EXTERNAL_DIFF: Programa externo para as operações de diff.

GIT_MERGE_VERBOSITY: Seta o nível de verbosidade da saída do comando merge

  • Miscelaneous

GIT_SSH: Controla o programa chamado nas operações sobre ssh (padrão: ssh).

GIT_ASKPASS: Controla o programa chamado quando o git pergunta por credenciais do usuário.

Git em Outras aplicações

Para usar o git em outras aplicações existem duas possibilidades:

  • chamar um shell e usar a interface d linha de comando do git.

  • Usar uma biblioteca.

Algumas das bibliotecas:

  • libgit2: Feita para C mas possui suporte externo para outras linguagens(pygit2, ...)

  • jgit: java :(

  • go-git: golang

  • dulwich: python puro

@Tomcat-42
Copy link
Author

💯

@Tomcat-42
Copy link
Author

👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment