🆘 Git tips - comandos úteis para sobreviver no dia a dia
Tags: git, codenewbie
Published: 2021-09-03 20:38:46

O versionamento de código ajuda muito nossa vida como desenvolvedores. Porém muitas vezes nos deparamos com algumas situações difíceis com o git no dia a dia...

Eu gosto de ir tomando notas sobre minhas descobertas conforme vou aprendendo e sobrevivendo para relembrar e consultar sempre que necessário.

Separei uma lista de comandos úteis (um pouco além dos mais básicos, e aqueles que geralmente a gente esquece), espero que te ajudem também 😉

Vamos lá...

---

*Substituir comando entre <>*

# # URL  

## Verificar qual a URL remota

```bash
git remote -v
```

## Editar url remota

```bash
git remote set-url origin <https://github.com/USERNAME/REPOSITORY.git>
```

---

# Stash  

📖 Opções de Git stash (ver [Atlassian](https://www.atlassian.com/git/tutorials/saving-changes/git-stash))

O comando git stash é utilizado para armazenar temporariamente as alterações que você fez, para poder trabalhar em outra coisa e depois voltar e reaplicá-las posteriormente.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6ovla8ny9rdct0b52mq.png)
_Fonte da imagem: Atlasian_

## Stash **tracked files**

```bash
git stash
```

## Stash também dos **untracked files**

```bash
git stash -u

```

onde `-u = --include-untracked`

## Stash de todos os arquivos, incluindo os **ignored files**

```bash
git stash -a
```

onde `-a = --all`

## Stash com descrição

É possível adicionar mensagens/descrições aos *stashs*, assim como fazemos com os commits:

```bash
git stash save <"message">
```

## Listar stashs

```bash
git stash list
```

## Deletar *stash* específica

```bash
git stash drop stash@{<index>}
```

## Deletar todas *stash*

```bash
git stash clear
```

## Reaplicando alterações que estão em *stash*

### Padrão, último *stash*

```bash
git stash apply
```

### Escolher qual *stash* (como em um array, utilize o `git stash list` para visualizar a lista de *stashs*):

```bash
git stash pop stash@{<index>}
```

## Visualizar Stash diff (stash show)

```bash
git stash show
```

### # ou, para visualização completa (-p = --patch):

```bash
git stash show -p
```

## Criar branch a partir de *stash*

```bash
git stash branch <branch-name> stash@{<index>}
```

---

# # Cherry Pick  

O cherry-pick é um comando para 'Pegar' um commit de uma branch através do hash do commit e aplicá-lo em outra.

Ex: commitei acidentalmente em outra branch, e desejo trazer o commit para minha branch certa.

## Pick 1 commit

```bash
git cherry-pick <hash>
```

## Pick vários commits

```bash
git cherry-pick <hash1> <hash2> <hash3>
```

## Pick de um commit até outro commit

```bash
git cherry-pick <hash1...hash3>
```

---

# # Branchs  

## Listar Branchs

```bash
git branch
```

## Listar branchs matching

```bash
git branch --list '<termo>*'
```

exemplo, listar branchs, cujos nomes começam com **fix/:**

```bash
git branch --list 'fix/*'
```

---

## Renomear branch

### Local, e se você está nessa branch

```bash
git branch -m <new-name>
```

### Local, e se você NÃO está nessa branch

```bash
git branch -m <old-name> <new-name>
```

### Remota, seguir os passos adicionais

```bash
git push origin :<old-name> <new-name>

# ou

git push origin --delete <old-name>
git push origin <new-name>
```

### Resetar a branch *upstream* para o novo nome da branch

```bash
git push origin -u <new-name>
```

---

## Remover tag de uma branch

### Remover tag, branch remota

```bash
git push origin :refs/tags/<tag-name>
```

### Remover tag, branch local

```bash
git tag -d <tag-name>
```

---

## Mudar para branch anterior [atalho]

```bash
git checkout -
```

---

# # Commits   

## Alterar (Reescrever) mensagem do último commit

para renomear o commit, caso este seja seu último commit:

```bash
git commit -m '<nova mensagem de commit>' --amend
```

- caso já tenha subido este último commit para a branch remota, será necessário fazer um push force pois estaremos sobreescrevendo a história
- caso não seja o ultimo commit, será necessário renomear através de rebase interativo ou reset —soft

## Refazer o último commit (add arquivos ao último commit)

### Refazer o último commit utilizando a mensagem do commit anterior

Considere ter esquecido alguma alteração em um arquivo após ter commitado. Você pode utilizar o `amend` para commitar de novo utilizando a mesma mensagem do último commit:

```bash
# primeiro add o arquivo (git add <arquivos>) e em seguida:

git commit --amend --reuse-message HEAD
```

ou

### Refazer o último commit

```bash
# primeiro add o arquivo (git add <arquivos>) e em seguida:

git commit --amend --no-edit
```

## Desfazer commits

- com **soft**: apaga só os commits
- com **hard**: apaga os commits e o código

### Desfazer o último commit

mantendo as alterações do último commit

```bash
git reset --soft HEAD^ 
```

deletando todas as alterações do último commit

```bash
git reset --hard HEAD^
```

### Desfazer commits por quantidade (do mais atual para o mais antigo)

Desfaz apenas os commits e mantem as alterações

```bash
git reset --soft HEAD~<quantidade de commits>
```

Desfaz os commits e o código

```bash
git reset --hard HEAD~<quantidade de commits>
```

### Desfazer commits até o commit x (com soft ou hard):

Através de um `git log --oneline`podemos verificar os commits, e obter a hash de referência.

```bash
git reset --soft HEAD~<hash>
```

o comando acima irá desfazer todos os commits posteriores à hash especificada.

---

# # Git log (lista de commits)  

## Listar commits resumido

```bash
git log --oneline
```

## Listar commits gráfico branch

```bash
git log --graph --oneline
```

## Listar commits com referências associadas (branch, tag, etc)

```bash
git log --decorate

# ou

git log --oneline --decorate
```

## Listar commits por quantidade

```bash
git log -<quantidade>

# ex: git log -5
```

## Listar commits pesquisa → procurar commits com uma mensagem/palavra

```bash
git log -S <'string-to-search'>
```

## Listar commits pesquisa → procurar commits com uma mensagem/palavra do código

```bash
git log -S '<string-to-search>'
```

## Listar commits pesquisa → procurar commits com uma mensagem/palavra da mensagem de commit

```bash
git log --grep='<string-to-search>'

# ex: git log --grep='fix'
# ex: git log --grep='fix' --oneline
```

## Listar commits pesquisa → procurar commits por arquivos

```bash
git log -- <file1.extension> <file2.extension> <...n>

# ex: git log -- foo.ts bar.ts
```

## Listar commits por data

### Depois de

```bash
git log --after='<date>'

# ex: 
# git log --after='2014-7-1'
# git log --after='yesterday'
# git log --after='1 week ago'
```

### Depois de

```bash
git log --before='<date>'

# ex: 
# git log --before='2014-7-1'
# git log --before='yesterday'
# git log --before='1 week ago'
```

### Entre datas

```bash
git log --since='<date>' --until='<date>'

# ex: git log --since='<JAN 01 2019>' --until='<DEC 25 2019>'
```

## Listar commits por autor

### 1 autor

```bash
git log --author='<name>'

# ex: 
#  git log --author='Lays'
```

### Mais de 1 autor

```bash
git log --author='<name1>\|<name2>'

# ex: 
#  git log --author='Lays\|Bruno'
```

## Listar último commit

```bash
git log -1
```

---

# # Push  

## Push force

Caso a gente reescreva a história de algo que já está commitado na branch remota, como por exemplo um squash, renomear commit etc, será necessário fazer um `push force` para forçar a atualização remota, já que ela irá recusar a atualização por `push` normal. Ou seja o `push force`, sobreescreve tudo o que está na branch remota pelo que está na branch local. Tome cuidado com esse comando, e nunca faça `push force` das branchs principais.

```bash
git push --force

# ou

git push -f

# ou 

git push origin +HEAD
```

## Fazer push sem digitar o nome da branch em que você está (HEAD) [atalho]

```bash
git push origin HEAD
```

---

# 🆘 # Reflog - o Salva vidas  

## Histórico - Listar tudo o que você fez no git

Enquanto o `git log` exibe apenas os commits, o `git reflog` exibe todo o histórico, incluindo  commits, checkout, merge, rebase etc.

```bash
git reflog
```

a partir da lista/histórico conseguimos reverter algumas alterações indesejadas.

## Algumas opções com git reflog

Após executar o `git reflog`, serão listadas todas as modificações. Procure o hash referente ao ponto que você gostaria de voltar no tempo. Algumas opções para trabalhar com o reflog:

- Reverter todas as alterações para o hash específico (deleta todas as alterações feitas):

    ```bash
    git reset --hard <hash>
    ```

- Reverter somente um arquivo específico para o estado em que estava a partir de um hash:

    ```bash
    git checkout <hash> -- <filename>
    ```

- Fazer Cherry-pick a partir do hash:

    ```bash
    git cherry-pick <hash>
    ```

---

# # Merge tips  

## sem fast-forward

```tsx
git merge --no-ff <branch-name>
```

> The --no-ff flag prevents git merge from executing a "fast-forward" if it detects that your current HEAD is an ancestor of the commit you're trying to merge. A fast-forward is when, instead of constructing a merge commit, git just moves your branch pointer to point at the incoming commit.

However, occasionally you want to prevent this behavior from happening, typically because you want to maintain a specific branch topology (e.g. you're merging in a topic branch and you want to ensure it looks that way when reading history). In order to do that, you can pass the --no-ff flag and git merge will always construct a merge instead of fast-forwarding.

_[https://newbedev.com/what-is-the-difference-between-git-merge-and-git-merge-no-ff](https://newbedev.com/what-is-the-difference-between-git-merge-and-git-merge-no-ff)

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cvxf2ouab9sllgvv3y4o.png)
_Fonte da imagem: NewBeDev_ 

# # Arquivos  

## Renomear arquivo local

## 1ª opção: renomear pelo computador

1. renomeie normalmente o arquivo pela pasta.
2. Faça `git add do arquivo`
3. Assim ele irá passar para o estado de RENAMED quando você verificar pelo `git status`
4. Agora faça o commit do arquivo normalmente com `git commit`

## 2ª opção: pelo Git

1. No terminal: `git mv nome_antigo.extensão novo_nome.extensão`
2. Assim ele irá passar para o estado de RENAMED quando você verificar pelo `git status`
3. Agora faça o commit do arquivo normalmente com `git commit` para consolidar a mudança

## Unstage Files

Se você deseja já fez `git add` em um arquivo e ele está em STAGE pronto para ser commitado, mas deseja reverter (sem perder as alterações):

Todos os arquivos:

```bash
git reset
```

Arquivo específico:

```bash
git reset -- <nome-do-arquivo>
```

## Desfazer alterações

Supondo que você deseja desfazer alterações no arquivo (apagar alterações)… vai depender em que ponto ele está: untracked, modified, commited.

* Ao invés de desfazer, o mais aconselhado é reverter, para ao invés de apenas deletar a alteração, manter documentado. Ver reverter mais abaixo.

### Desfazer alterações: arquivo em :::untracked:::

```bash
git checkout --<nome_do_arquivo.extensão>
```

## Desfazer alterações: arquivos em :::modified::: (já feito add, mas não commit)

1. 1º tira ele de modified e leva de volta para untracked:

    ```bash
    git reset <nome_do_arquivo.extensão>
    ```

2. 2º já é possível fazer checkout e reverter alterações

    ```bash
    git checkout --<nome_do_arquivo.extensão>
    ```

## Desfazer alterações: arquivos já commitados

### 1º caso SOFT

Tirar arquivo de commit e passar de volta para staged, sem deletar o arquivo, usa-se o comando –soft + a hash do pai, ou seja, a hash do commit anterior ao que eu quero apagar. e depois é possível fazer o checkout.

```bash
git reset --soft <hash_do_pai>
```

ou através da quantidade de commits (voltar atrás em nº de commits):

```bash
git reset --soft HEAD~<numero de commits>
```

### 2º caso MIXED

Tirar arquivo de commit e passar para modified (fora do staged), sem deletar o arquivo, usa-se o comando –mixed + a hash do pai, ou seja, a hash do commit anterior ao que eu quero apagar e depois é possível fazer o checkout.

```bash
git reset --mixed <hash_do_pai>
```

ou

através da quantidade de commits (voltar atrás em nº de commits):

```bash
git reset --mixed HEAD~<numero de commits>
```

### 3º caso DELETAR HARD

Tirar arquivo de commit e deletar o arquivo (todos os commits e arquivos que estão depois do que o commit em questão deixam de existir, são deletados e fica só do commit pai/anterior para baixo). Usa-se o comando –hard + a hash do pai, ou seja, a hash do commit anterior ao que eu quero apagar e depois é possível fazer o checkout.

```bash
git reset --hard <hash_do_pai><hash_do_commit_a_ser_revertido>
```

ou

através da quantidade de commits (voltar atrás em nº de commits):

```bash
git reset --hard HEAD~<numero de commits>
```

## Reverter alterações

Quase semelhante ao desfazer, mas nesse caso será criado um commit que indica a reversão. É o mais aconselhado.

### 1° caso

Com mensagem sobre a reversão, neste caso o editor de texto irá abrir para que você insira a mensagem sobre o por que da reversão, ou digite (-m “mensagem”) após o hash

```bash
git revert <hash_do_commit_a_ser_revertido>
```

### 2° caso

Sem mensagem sobre a reversão:

```bash
git revert <hash_do_commit_a_ser_revertido> --no-edit
```

## Desfazer: arquivo deletado da máquina

```bash
git checkout -- <nome_do_arquivo.extensão>
```

## Remover arquivo/pasta pelo Git

### Remover arquivo

```bash
git rm <nome_do_arquivo.extensão>
```

### Remover pasta

```bash
git rm -r <nome da pasta>
```

## Desfazer alterações

### Desfazer todas as alterações (untracked)

- visualizar arquivos que estão fora da *working tree*:

    ```bash
    git clean -n -d
    ```

- deletar arquivos:

    ```bash
    git clean -f -d
    ```

### Desfazer todas as alterações (tracked)

```bash
git checkout .
```

### Voltar para versão anterior de arquivo (checkout)

```bash
git checkout <hash> <file-name.extension>
```

## Remover arquivo adicionado acidentalmente

### Arquivo ainda não commitado:

```bash
git reset </path/file-name.extension>
```

### Arquivo já commitado:

### Desfazer merge e manter o histórico de commits

```bash
git reset --soft HEAD~1

git reset </path/file-name.extension> 

rm </path/file-name.extension>

git commit
```

ir para a branch principal

```bash
git checkout <master_branch>
```

git log para verificar a hash correta

```bash
git log --oneline
```

fazer a reversão utilizando a hash do merge correspondente

```bash
git revert -m 1 <merge-commit-hash>
```

# # Squash (‘comprimir’ commits em um só)  

Considerando que você deseja comprimir/transformar seus últimos 1 só.. para isso fazemos o squash.

- desfazer os últimos commits por quantidade (mantendo as alterações):

```bash
git reset --soft HEAD~<commit_quantity>
```

ex, desfazer 5 commits: `git reset --soft HEAD~5`

ou você pode optar por utilizar as hashs dos commits. O comando abaixo listará os commits, assim você pode verificar até qual commit você quer desfazer.
(lembrando que os commits são listados do mais novo para o mais antigo)

```bash
git log --oneline
```

em sequida:

```bash
git reset --soft <hash_do_ultimo-commit_que_vc_quer_manter>
```

ex:

```bash
git log --oneline

# listou:
<x323x32> meu commit 6
<kj56kj5> meu commit 5
<8f7g87f> meu commit 4
<k6k356j> meu commit 3
<jk4hj34> meu commit 2
<hjh2424> meu commit 1

# supomos que você deseja desfazer os 3 primeiros commits 
# (hash_6, hash_5, hash_4) e manter a partir do hash_3, então você usará
# o código do hash 3

git reset --soft k6k356j
```

- faz o processo de add e commit com a mensagem certa
- faz push para o repositório remoto

---

# # Configurações globais  

## Verificar e editar configurações globais

```bash
git config --global -e
```

## Configurar usuário e email

```bash
git config --global user.name <name>
git config --global user.email <email>
```

## Configurar editor padrão

```bash
git config --global core.editor '<editor_name> --wait'
```

exemplo com o VSCode:

```bash
git config --global core.editor 'code --wait'
```

---

# # Remover Git no repositório  

Se por algum motivo não deseja mais usar o controle de versões e deseja 'desligar/remover' o Git do repositório (esse comando irá remover/deletar o Git do repositório em questão):

```bash
rm -rf .git/
```

Este comando irá deletar o arquivo onde o git guarda todas as informações e configurações do repositório. Pode ser feito dessa forma, ou deletando o arquivo manualmente.

--
_Foto de capa: <a href="https://unsplash.com/@yancymin?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Yancy Min</a> on <a href="https://unsplash.com/s/photos/git?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>_