Advance Git course notes - Frontend Masters by Nina Zakharenko
Published: 2021-09-28 21:14:33

These are my notes from [Nina Zakharenko's Git course on FrontendMasters](https://frontendmasters.com/courses/git-in-depth/). [Repo can be found here](https://github.com/nnja/advanced-git). Well good luck to me! :)

On windows, the equivalent of `tree .git` in Mac is `tree.com //a //f` when inside the folder we want to map. For instance, `.git`. [Source](https://superuser.com/a/1312725).

## Plumbing commands

`echo 'Hello, World!' | git hash-object --stdin` returns a SHA1: 8ab686eafeb1f44702738c8b0f24f2567c36da6d. `--stdin` is because otherwise it expects a file.

^ in Mac we get the same with `echo 'blob 14\Hello, World!' | openssl sha1`

`git init` creates `.git` folder, which contains data about our repo.

#### git hash-object

`echo 'Hello, World!' | git hash-object -w --stdin` we run it now with the `-w` flag (Write)

The hash has been saved in directory `objects`, folder `8a` (first 2 chars of hash), which stores the rest of the hash: `b686ea`. But the blob (which stores the hash) is missing filenames and directory. Git stores this information in a `tree`. A tree contains **pointers** (using SHA1) to:

- blobs
- to other trees

And **metadata**:

- type of pointer (blob or tree)
- filename or directory name
- mode (executable file, symbolic link, etc)

#### git cat-file

`git cat-file -t 8ab68` (first few digits of hash) `-t` prints the type of the hash
`git cat-file -p 8ab68` (first few digits of hash) `-p` prints the content of the hash

We don't have to type the whole hash because, unless your repo is massive (i.e. linux kernel), git can figure out the hash with the first few characters. Otherwise, git will tell you..

#### git config

`git config --global core.editor <YOUR_EDITOR>`

emacs: `emacs`
vi: `vi` or `vim`
atom: `atom --wait`
sublime: `subl -n -w`
vscode: `code --wait`

#### git ls-files

`git ls-files -s` shows what's in the staging area:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hj7tt4yhpd45umkjcnlv.png)
 

## Commits (slide ~30)

A commit is a code snapshot at a point in time. They point to a tree and contain metadata:

- author and committer
- date
- message
- parent commit (one or more)

The SHA1 of the commit is the hash of all this information.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vff4g0wwuy7tbua11dqa.png)
 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oriyj9y72l3ihjkv8nho.png)

We can't change commits because any data change will have a new hash. So even if same content, date will change so hash will change.

## References - pointers to commits

2 places where references are stored:

- `.git/HEAD` file
- `.git/refs/heads` is where all branches live

`git log --oneline` tells me which commit HEAD is pointing to. 
`git log --oneline --graph` add a graphical component to it

`cat .git/refs/heads/main` will print hash of ^ commit where HEAD is pointing to (which commit branch points to) 

`cat .git/HEAD` shows that, at this point in time, HEAD (our current branch pointer) is also pointing to main. And main is pointing to the initial commit.

`git show-ref --heads`

#### Tags 

Simple pointer to a commit. When a tag is created with no arguments, it captures the value in HEAD.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2l7f0ce7f7doiprl3buz.png)

`git tag -a` annotated tags. Points to a commit but stores additional information. i.e. `git tag -a v1.0 -m "Version 1.0 of my blog". `git tag` will print commit tag is pointing to. `git show v1.0` will print all the additional information.

`git tag` lists all the tags in a repo
`git show-ref --tags` lists all tags and commits they are pointing to
`git tag --points-at <commit>` list tags pointing to a commit
`git show <tag-name>` list info about tag

The commit that a tag points to does not change, it is a snapshot.

#### Branches 

Pointer to a particular commit. The pointer of the current branch changes as new commits are made.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2iedbsoolvh39jngdlsc.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4pk8t2s2r0c77lnabdn7.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ep8ss0flttecov0g6jv3.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t544kwkj8wbdomzigti6.png)

The current branch pointer moves with every commit to the repository.

#### HEAD 

(a special type of reference) a pointer to the current commit (the very last commit you made). That is how git knows what branch you are currently on and what the next parent will be. Points to the **name** of the current branch but it can point at a commit too (detached HEAD). HEAD moves when you commit in current active branch or when you checkout a new branch.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a66nz3ob1ru3feb5u3jk.png)

##### HEAD-LESS / DETACHED HEAD STATE

When you checkout to a specific commit or tag instead of a branch. There is no reference pointing to the commits you made in a detached state. If you want to save your work: `git branch <new-branch-name> <last-commit>`. If you don't point a new branch at those commits, they will no longer be referenced in git (**dangling commits**) and will be garbage collected. 

## 3 AREAS WHERE CODE LIVES

#### WORKING AREA (wORKING TREE)

Also called `untracked files`. Files in working area **not** in staging are not handles by git.

#### STAGING AREA (aka CASH, INDEX)

What files are going to be part of your next commit. This is how git know what will change between your current commit and your next commit. 

A clean staging area isn't empty. It is an exact copy of the latest commit. When files are added or removed from the staging area git knows because the SHA1 of your files is different from the ones in your repository.

`git add <file>`

`git add -p` allows to stage in chunks, interactively. Useful if you have done too much work for one commit and you want to break it out. -p for partial?

`git rm <file>` remove file

`git mv <file>` rename file

`git reset hello.txt` removes the files from the staging area, without changing the file in the working area 

`Unstaging` files doesn't remove the files, it replaces them with a copy currently in the repository. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09idai8xp53lmxo8esee.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y21xsma9war43occgdib.png)
  
#### REPOSITORY

The files git knows about. Contains all of your commits. In your .git directory.

#### GIT STASH

save un-commited work and it is safe from destructive operations.

`git stash`
`git stash list`
`git stash show stash@{0}` show contents of this stash
`git stash apply` apply the last stash
`git stash apply stash@{0}` this is the same as `git stash apply` because it applies stash 0, which is the last one.

`git stash --include-untracked` by default git only stages files that are already tracked - in the repo or in the staging area. What if you have created a file that you are not ready t move to the staging area? Once you are back, the untracked files are still untracked
`git stash --all` will stash all files, include the ignored

`git stash save "WIP: making progress on foo"` name the stash for easy reference 

`git stash branch <optional branch name>` start new branch from a stash

`git checkout <stash name> -- <filename>` grabs a single file from a stash. if you have changes in your working area when the stash is applied the changes will be overwritten, so careful!

`git stash pop` removes the last stash and apply the changes
`git stash drop` removes the last stash
`git stash drop stash@{n}` removes the nth stash
`git stash clear` removes all stashes

## MERGE AND REBASE

#### MERGE COMMITS

They are just commits. Marker of when a new feature is merged into `master`.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wz09951k30jlu81815sv.png)

#### FAST FORWARD 

You checkout from `master`, you work on your feature, and there have not been any changes to `master`. When merging into `master` git shows the message `fast-forward`. Feature commits are added on top of `master` and the pointer of `master` is moved to the tip:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pudmznzchkxtnrsow9uk.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/acey0aee5v9hs3ejsk7e.png)
 
The danger is that we lose track of the feature branch, because there is a linear commit history. To avoid this, you can specify `--no-ff`:

`git merge --no-ff` it will foce a merge commit even when one it is not necessary.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1vktbsqsx16tlypi5kq.png)

#### MERGE CONFLICTS

Attempt to merge, but files have diverged. Git stops until conflicts are resolved. Git will try, but when it can't it will stop. Git creates a new file with the conflicts. 

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ynog7vwpg9xndhiwv7s4.png)

##### GIT RERERE - **RE**use **RE**corded **RE**solution

Git saves how you resolved a conflict and, in the next conflict, reuse the same resolution. Useful for:

- Long lived feature branch (like a refactor)
- Rebasing

Turn it on: `git config rerere.enabled true` turns rerere in this project. If you want it for all your projects, use `--global` flag when calling `git config`.

`git rerere diff` will show what is going on with the conflict.

## HISTORY AND DIFFS

Good commits are important and help preserve teh history of a code base. Anatomy of a good commit message:

- `git commit -m` is fine if the commit message is brief and is one liner. If you need loger, `git commit` will open up the editor.
- Future tens: fix vs fixed.
- Short subject, followed by blank line. Description of current behaviour and short summary of **why** the fix is needed.

#### GIT LOG

`git log` is the basic command. But can be cooler:
`git log --since="yesterday"
`git log --since="2 weeks ago"
`git log --name-status --follow -- <file>` to follow logs for a specific file, even if it changes names!

[image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c18xngxv6zvi5os4gzzn.png)
^ A = Added, M = Modified, R = Renamed? 

`git log -grep <regexp>` or `git log -grep="whatever"` search for commit messages that match a regular expression or whatever. i.e. `git log --grep=mail --author=nina --since=2.weeks`

##### DIFF-FILTER

Allows to include or exclude files that have been (A)dded, (D)eleted, (M)odified & more.

`git log --diff-filter=R --stat` R for Renamed
`git log --diff-filter=M --oneline` finds commits that have modified files
`git log --diff-filter=R --find-renames`

##### REFERENCING COMMITS

`^` or `^n` - no args is like `^1`: the first parent commit. `n` is the nth parent commit. 
`~` or `~n` - how many commits follow back from the first parent. `n` number of commits back, following only 1st parent.

`^` and `~` can be combined.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ee7r1jq8sewefgqlf4dm.png)

#### GIT SHOW

Look at a commit.  

`git show <commit>` show commits and contents
`git show <commit> --stat`show files changes in commit
`git show <commit>:<file>` look at a file from another commit

i.e. `git show e47e1cd`

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7m56pc0bzocpqe6pxq87.png)
 

i.e. `git show e47e1cd --stat --oneline`

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k5st3koynbziuokm9ej8.png)
 
#### GIT DIFF

Shows changes between commits, between staging area and the repository, what's in the working area.

`git diff` unstaged changes (what could be in the next commit)
`git diff --staged` staged changes (what will be in the next commit). 

^ You can pass file arguments to see a specific file.

`git diff A B` will show changes in B, that are not in A. Same as `git diff A..B`.

#### DIFF BRANCHES

`git branch --merged master` which branches are merged with master, and be cleaned up
`git branch --no-merged master` which branches aren't merged with master yet

## FIXINGS MISTAKES (checkout, reset, revert, clean)

#### GIT CHECKOUT

Allows to restore tree files or switch branches

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnsza61sh8w6el0q0vdi.png)

##### What happens when we `git checkout` a branch?

1. Change HEAD to point to the new branch
2. Copy commit snapshot to the staging area (also called index)
3. Update the working area with the branch content
 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vhmx6nhr1ghvky0cv6xl.png)

##### What happens when we `git checkout -- <file_path>`? 

`--` indicates to git the end of the command and the beginning of the arguments. In case branch and file name are the same, `--`indicates to git that we want the file.

Replace the working area copy with the version from the current staging area.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7alj0m94qbmg81atlh70.png)
 
##### What happens when you `git checkout <commit> -- <file_path>`?

Update staging area to match the commit and update the working area to match the staging area.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1wpi0uun0rhm3sp5bq7f.png)
 
##### Restore a deleted file

`git checkout <deleting_commit>^ -- <file_path>` `^` indicates parent so we are restoring the commit before file got deleted.

#### GIT CLEAN

How to clean working area? `git clean` deletes untracked files. Use the `--dry-run` flag to see what would be deleted. The `-f` flag to do the deletion. `-d` will clean both files and directories.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rrezq088yii7x54vfxla.png)

#### GIT RESET

Reset performs different actions depending on the arguments:

- With a path
- Without a path

By default, git performs `git reset --mixed`.

`git checkout` will move the HEAD but the branch stays where it was. `git reset` will move the HEAD and the branch reference, meaning the branch is now modified.

For commits: moves the HEAD pointer, optionally modifies files.
For file paths: does not move HEAD pointer, modifies files.

3 options for `git reset`:

##### GIT RESET --SOFT: moves HEAD

`git reset --soft HEAD~` now HEAD points to the previous commit (because `^` indicates parent of the current commit). 

Before:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99ztp3pzo53qo3shfc31.png)
 
After:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmnpnyhkz4q1hned4z53.png)

##### GIT RESET --MIXED (the default): move HEAD, copy files to stage

Before:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a9xob3c40qzs0s5molow.png)
 
After:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bdbjppul3wib099f6gk2.png)

##### GIT RESET --HARD: move HEAD, copy files to stage & working! (destructive operation because you lose files untracked in the working area)

Before:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o2ueepgdikvl5xeam0he.png)
 
After:
[image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/62rjgpys95afop3w4xti.png)

`git reset --hard` cleans staging and working trees.

##### CHEATSHEET GIT RESET <COMMIT>:

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sg736il0u95jhqkze1ea.png)
 
##### GIT RESET -- <FILE>

Doesn't move the HEAD pointer but resets file in staging area. 

Before:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0zpdp4ecrx2m2fdals1b.png)
 
After:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/01zrqqspj2jasb0g67y3.png)

##### GIT RESET <COMMIT> -- <FILE>

Same thing as `git reset -- <file_path>` - copies files from commit whatever into staging area.

Before:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7qju1jj3llsb6ci6j0hd.png)
 
After:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jl7rxwf0559o8isofh52.png)

##### CHEATSHEET GIT RESET <COMMIT> -- <FILE>

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxpvjwuhxqkiyn2ijep5.png)

##### UNDO A GIT RESET WITH `orig_head`

In case of an accidental `git reset`. Git keep the previous value of HEAD in variable called `ORIG_HEAD`. To go back to the way things were: `git reset ORIG_HEAD`.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3fmh6ijqlovkdqafwglo.png)

#### GIT REVERT - THE SAFE RESET

`git revert` creates a new commit that introduces the opposite changes from the specified commit. The original commit stays in the repository.

Tip: use `git revert` if undoing a commit that has already been shared. revert **does not** change history.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4zm4bojpo7d0h0twf4yj.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sg4m2vnmisslpt40khb5.png)
 
## REBASE, AMEND - REWRITE HISTORY!

#### AMEND A COMMIT

`git commit --amend` Quick and easy shortcut that lets you make changes to the previous commit.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3fopue54hgzu1hkrjuod.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tmfs0g2eeu4y0yj06yi3.png)

## REBASE = give a commit a new parent (i.e. a new "base" commit)

Imagine feature branch and master branch have diverged. We don't want a messe merge commit in our history. We can pull in all the latest changes from master, and apply our commits on top of them by changing the parent commit of our commits.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ej96tvge8g9ob64tatq.png)
 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ff1pfof7saazo0kii37s.png)
 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/klgc8ynb2wnix39r55ic.png)
 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/48x4k5xizf10flvgp7y3.png)
 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p3hp97xu1thyvyiuamnb.png)
 
##### MERGE VS REBASE

Rebase is cleaner because it doesn't create a new commit.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l2urk9m1qhyoxi76w0c5.png)

##### INTERACTIVE REBASE

Commits can be edited, removed, combined, re-ordered, inserted. **Before** they are "replayed" on top of the new HEAD.

`git rebase -i`or `git rebase --interactive` and opens up an editor with the "todos". 

Interactive rebase with a shortcut: `git rebase -i <commit_to_fix>^` (the `^` specifies the parent commit).

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b5qfaziipe5q35wfd1g9.png)
 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yz27mprms9zoi9eswwal.png)
 
 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0lkx8i4aiwifrsya7gsn.png)

##### REBASE TO SPLIT COMMITS

Editing a commit can also split it up into multiple commits!

 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztznxrxar5wc17brty31.png)

#### FIXUP AND AUTOSQUASH

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vit78udork7wcqpowxef.png)
 ![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uk8frsvomgcdllhievnx.png)
 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kiq21vq8541f4ptk0s80.png)
 
#### GIT REBASE --ABORT

At any time before rebase is done, if things are going wrong: `git rebase --abort`.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vqxzrsph8c5gz7bh827b.png)

Git best practice: `commit often, perfect later, publish once`. 

When working locally:

- Commit whenever you make changes
- It will help you be a more productive developer.
- Before push work to a shared repo, rebase to clean up the commit history.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wop0o0m2tn1a39e6z38l.png)

**CHECK EXERCISE 7 SOLUTIONS FOR EXAMPLES ABOUT REBASE -I [HERE](https://github.com/nnja/advanced-git/blob/master/exercises/Exercise7-RebaseAndAmend.md)**

## GITHUB AND REMOTE REPOS

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3la4zsj0a88deq12i6lo.png)

`origin` name that GH gives to the server you cloned from. Cloning a repo from a URL will fetch the whole repo and make a local copy in your .git folder.e remotes 

`git remote -v` see remote you have set up

What if you clone someone's repository? You can pull the changes, but you cannot push.

#### FORK

GH concept. Copy of repo stored in your GH account. You can clone your fork to your local computer. And because that repo is in your account, there are no no restrictions. If you want to merge changes to the original project from a fork, you do that via a PR (Pull Request).

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2e5qr7nyhil81kjdwx7f.png)

If you want your fork to stay up to date (while you work on your work, other changes are getting merged into the source repository) you need to set an **upstream**. 

Upstream is the base repot you created the fork from. This isn't set up by default, **you need to set it up manually**. By adding an upstream remote, you can pull down changes that have been added to the original repo after you forked it.

`git remote add upstream https://github.com/ORIG_OWNER/REPO.git`
 
#### GH WORKFLOW

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jgn4qmtlkpd9srlgaior.png)

#### TRACK A BRANCH

Track a branch to tie it to an upstream branch. Use `git pull` / `git push` with no arguments.

To checkout a remote branch, with tracking: `git checkout -t origin/feature`.

Tell Git which branch to track the first time you push: `git push -u origin feature` (it sets tracking and push that branch to remote).

`git branch` can be improved with `git branch -vv` to show which upstream (or remote branch) you are tracking in your remote branch and how many commits behind you are.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mure3o32g9z2a47g1s4h.png)

## GIT FETCH

Keeps your local repository up to date with a remote. It pulls down all the changes that happened on the server. But it **does not** change your local repository.

#### GIT PULL

`git pull` will pull down the changes from the remote repo to your local repo, and merging them with a local branch.

Under the hood: `git pull` = `git fetch && git merge`

If changes happened upstream, wit will create a merge commit. Otherwise, it will fast-forward.
 
#### GIT PUSH

`git push` sends your changes to the remote repo. Git only allows to push if your changes don't cause a conflict. To see commits which haven't been pushed upstream yet, use: `git cherry -v`. 

#### GIT PULL --REBASE

`git pull --rebase` will fetch, update local branch to copy the upstream branch, then replay any commits you made via rebase. When you open a PR, there will be no unsightly merge commits.  

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h32rpxqq50omvdwij6ms.png)

#### NOTE ON TAGS

Git doesn't automatically push local tags to a remo repo, you need to do it manually. To push tags: `git push <tagname>` or `git push --tags`.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vjr684cah33c315dz4ky.png)

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zk0uhw98vvt9jk00jla.png)
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9cl734co285rtqrnaqtb.png)
 

## DANGER ZONE

These are all destructive actions:

`git checkout -- <file>>` if the file is present in staging area it will be overwritten

`git reset --hard` will overwrite changes that are stahed and in the working area

Unless changes are staged, there is no way to recover them. 

Use `git stash --include-untracked` to include working area changes in your stash.

## REMOTE DESTRUCTIVE OPERATIONS - REWRITING HISTORY

- Rebase
- Amend
- Reset

If your code is hosted or shared, **never run `git push -f`**

## HOW TO RECOVER LOST WORK

Use `ORIG_HEAD`: the commit HEAD was pointing to before a: `reset`,  `merge`. Check for repository copies: github, coworker.

![Screenshot 2021-10-08 at 09.24.16](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6zjqex4nw5w3nb429p3y.png)
![Screenshot 2021-10-08 at 09.25.17](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6dph5ey2ycph3llxb0b.png)
![Screenshot 2021-10-08 at 09.25.54](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lpxa7mccnhuiebtpukbd.png)

## GITHUB

#### NAVIGATE LIKE A PRO

![Screenshot 2021-10-08 at 09.27.01](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1uess75bp9xdgw6ksuv0.png)

Up to date list of shortcuts [here](https://docs.github.com/en/get-started/using-github/keyboard-shortcuts). 

#### CONTINUOUS INTEGRATION (CI)

![Screenshot 2021-10-08 at 09.32.27](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ct346mg9d2b2et0f29j.png)

Travis CI integrates with GH:

![Screenshot 2021-10-08 at 09.33.09](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4nefgbwkq4zj54yqfzlo.png)
  



## MISC

`git branch a-new-branch` creates a branch but doesn't switch to it. Contrary to `git checkout -b a-new-branch`, which switches to it.
`git checkout -` switched to the previous branch we were in