Um arquivo com o nome de .gitignore dentro da raiz do repo fará que o git ignore todos os arquivos dentro dele.
$*git init*
$*git clone [URL]*
$*git status*
$*git add [FILE]*
$*git diff*
$*git diff (--cached|--staged)*
$*git commit -m [MENSAGEM]*
$*git commit -a -m [MENSAGEM]*
- 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]*
$*git log*
$*git commit --amend*
$*git restore [FILE]*
$*git remote -v*
$*git remote add [NOME] [URL]*
$*git fetch [REMOTE_NAME]*
- OBS: $git pull = $git fetch + $git merge
$*git push [REMOTE_NAME] [BRANCH]*
$*git remote show [REMOTE_NAME]*
-
Remover -> $git remote remove [REMOTE_NAME]```
-
Renomear ->
$*git remote rename [REMOTE_NAME] [NEW_NAME]*
$*git 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]*
$*git show [TAG_NAME]*
$*git tag -v [TAG_NAME]*
- Somente uma tag
$*git push [TAG_NAME]*
- Todas as tags
$*git push --tags*
$*git branch -v*
$*git branch [BRANCH_NAME]*
$*git branch -d [BRANCH_NAME]*
$*git checkout [BRANCH_NAME]*
- OBS:
$*git checkout -b [BRANCH_NAME]* cria e muda para a nova branch
$*git merge [BRANCH]*
$*git mergetool [FILE]*
$*git branch --merged/--no-merged*
$*git push [REMOTE] [LOCAL_BRANCH]:[REMOTE_BRANCH]*
$*git checkout -b(--track) [LOCAL_BRANCH] [REMOTE_BRANCH]*
$*git push --delete [REMOTE] [BRANCH]*
O rebase deixa a história de commits mais linear
$*git rebase [MASTER_BRANCH] [TOPIC_BRANCH]*
$*git checkout [MASTER_BRANCH]*
$*git merge [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
- 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
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.
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.
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.
O gitosis é um gerenciador de acesso e de chaves públicas para os projetos git no servidor.\ info
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.
- 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
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
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.
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*
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
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
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]
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]*
É ú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]
- 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.
- 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
### 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:
### 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)
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
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/*
Para mencionar um usuário, preceder seu username com um @. Quando um usuário é mencionado ele receberá uma notificação.h
- 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.
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.
- 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
Para abrir um shell interativo da staging area:
$git add -i(--interactive)
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
- 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.
- 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]
É 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
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]
Para ignorar diferenças de espaços em branco em merges, a flag --Xignore-space-change
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.
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
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]
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
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
.
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
- 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]
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
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]
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]
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]
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]
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
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
- 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.
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
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
.
- 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.
- 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.
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]
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
- 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.
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
💯