> For the complete documentation index, see [llms.txt](https://kdongs.gitbook.io/kdocs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kdongs.gitbook.io/kdocs/git/git.md).

# Git

## Staging files

### `add`

#### Adding files to stage (`add`)

Add all uncommited files for staging.

```bash
git add .
```

Add only selected files.

```bash
git add file1.ts file2.ts ...
```

#### Adding and Removing multiple files to stage (`add -i`)

You can iteractively *remove* or *add* from stage as.

```bash
git add -i
```

Then you can use options:

* `3`: To revert (remove) files from the staging area.
* `4`: To add files to the staging area.

#### To select changes in a file, and commit them separatly (`add -p`)

```
Useful when you made multiple changes in the same file, but want to make different commits for some of the changes.
```

```bash
git add -p
```

This will make you select `hunk`s *(Chunks)* of the code that will be commited.

### `reset`

#### Removing files from stage (`reset`)

To remove a file from the stage area.

```bash
git reset -- file1.ts
```

To remove all from the stage area.

```bash
git reset --
```

### `diff`

#### To see what is changed in the staging area (`diff --staged`)

```bash
git diff --staged
```

## Commiting

### `commit`

#### Create commit (`commit`)

```bash
git commit -m "Some commit message"
```

#### `commit -S`

`-S` will tell Git to make the commit using the configured `signinkey`. *(GPG signatures)*

```bash
git commit -S -m "Some commit message"
```

#### `commit --amend`

**Fix the last created commit message.**

This has to be un-pushed commits.

This will update the *LAST* commit.

```bash
git commit -m "Fixed commit message" --amend
```

### `reset`

#### Fixing several un-pushed commits (`reset`)

Must be on un-pushed commits. (*Already pushed commits must be fixed with \`?\`*)

The `reset` can accept:

* A `commit ID` as target.
* A syntax of `HEAD~2`, specifing that must go back 2 commits before the HEAD.

#### `--hard` reset

Which will move the `HEAD` to the specified commit AND revert all the changes done in the code.

{% hint style="warning" %}
**Useful when you dislike what you did and want to do a** `ctrl-z`**.**
{% endhint %}

{% hint style="info" %}
Commits reseted with `--hard` are only marked for deletion, so you can revert back if needed.

The changes done WILL be deleted when git runs it's garbage collector, which it does from time to time or manually, [#garbage-collector](#garbage-collector "mention").
{% endhint %}

```bash
git reset --hard bcaag55
```

#### `--soft` reset

Will only move the `HEAD` to the specified commit. *(This means that will only UNDO the erase the commits, so you can commit them again)*

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

### `rebase`

#### Fixing several un-pushed commits (`rebase`)

Must be on un-pushed commits. (*Already pushed commits must be fixed with \`?\`*)

An official way of fixing multiple done commits is with `rebase`.

`-i` will open a window for you to tell rebase what to do with the commits.

```bash
git rebase -i HEAD~3
```

| Options  | Description                                           |
| -------- | ----------------------------------------------------- |
| `pick`   | Use commit.                                           |
| `reword` | Use commit, but edit the commit message.              |
| `edit`   | Use commit, but stop for amending.                    |
| `squash` | Use commit, but meld into previous commit.            |
| `fixup`  | Like `squash`, but discard this commit's log message. |
| `exec`   | Run command *(the rest of the line)* using shell.     |
| `drop`   | Remove commit.                                        |

{% hint style="info" %}
**Tip:** For this you can leave the first commit on the list as `pick` and the others as `squash`.
{% endhint %}

## Logging

### `log`

#### Show commit logs from the current branch (`log`)

```bash
git log
```

#### Show logs formatted in a one line

```bash
git log --pretty=oneline
```

#### Show logs with GPG signatures

```bash
git log --show-signature
```

#### Show only last `n` logs

```bash
# the last
git log -1

# last 3 logs
git log -3
```

## Branches

### `branch`

#### Creating branches with (`branch`)

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

#### Deleting branches with (`branch -D`)

```bash
git branch -D <branch-name>
```

### `checkout`

#### Create branches and checkout to them with (`checkout -b`)

```bash
git checkout -b <new-branch-name>
```

## Tagging

### `tag`

There are two types of tags `lightweight` and `annotated`.

`lightweight` tags are just a simple tag name pointing to a commit.

`annotated` tags are stored as full objects in Git, containing a tagger name, email, date and a message.

{% hint style="danger" %}
By deafult `git push` doesn't transfer tags to remote servers.

* Explicitly push a specific tag with `git push origin <tag-name>`.
* Explicitly push all tags with `git push origin --tags`.
  {% endhint %}

#### Create annotated tags with (`tag`)

```bash
git tag -a <tag-name> -m "Tag message"
```

#### Create `lightweight` tags with (`tag`)

Will create a tag pointing to the last commit.

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

#### Create tags to specific commits with (`tag`)

```bash
git tag -a <tag-name> <commit-id>
```

#### Delete tags

Delete tags from local repository with:

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

However this will not remove it from the remote server, to do it:

```bash
git push origin --delete <tag-name>
```

## Save Uncommited Work

### `stash`

#### Stash work in a branch with (`stash`)

{% hint style="warning" %}
Must be done on `staged` files.
{% endhint %}

```bash
git stash
```

#### To unstash the work with (`stash pop`)

```bash
git stash pop
```

#### To list the WIP (Work in Progress) stashes

```bash
git stash list
```

### `diff`

#### Save work done to a `.patch` file with (`diff`)

{% hint style="warning" %}
Must be done on `staged` files.
{% endhint %}

```bash
git diff --staged > <file>.patch
```

#### Apply `.patch` file to working branch with (`apply`)

```bash
git apply <file>.patch
```

## Garbage Collector

Git runs it's garbage collector from time to time or manually with:

```bash
git gc
```

The garbage collector will delete changes done that were deleted with `reset --hard` for instance.

## Rewriting git commit history (`BFG Repo-Cleaner`)

The commits `sha1` which are the commits ID, use the commits files to be created. This means that if you re-write a commit without a file or with a file changed, it's `sha1` will change.

The git history structure is a graph, where each commit knows where it belongs by knowing the previous commit's `sha1`. So if you change one of the commits, you will change it's `sha1` and break all the git history.

To do this safely without breaking everything, you can use `bfg`, that will allow you to change a commit and then re-write all of the structure, maintaining all the graph.

**Installing `bfg`**

{% embed url="<https://rtyley.github.io/bfg-repo-cleaner>" %}

## Dealing with large files (`lfs`)

Files that are not `text` are interpreted by git as `binary` and these cannot have their *deltas* checked and done. This means that their changes cannot be tracked, so when commited, these files are copied in its entirety and attached to the commit.

So the more changes are made in this files and commited, the more number of files you will have in the project, and this will raise considerably the size of the project.

#### To deal with this use `lfs`

When using `lfs` the file itself does not go in the commit, instead only a reference to the file goes to the commit.

So when `pulls` are executed or when the project is cloned, only the last version of these big files are downloaded, and not all the files versions.

On linux install it with:

```bash
apt install git-lfs
```

Then on the project root you initialize it with:

```bash
git lfs install
```

Then tell git what types of files to use it on `lfs`.

```bash
git lfs track "*.mp4 *.jpg *.psd ..."
```
