# Git and Github

## GIT

## Gotchas

### How to remove .DS folder in mac&#x20;

When we first initialize git, using git init, our working folder turns into a working directory where .git folder is created. Not only this, but when you use Mac, for some reason, **.DS** folder gets created. You can do git status and you see this folder. We can remove this as shown below.

{% embed url="<https://stackoverflow.com/questions/107701/how-can-i-remove-ds-store-files-from-a-git-repository>" %}
Removing .DS folder (I've upvoted for this)
{% endembed %}

## Basics

* A general idea -> We have 3 areas

![General Diagram](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Ft5xCIwxhzCFWXFWU97GU%2Fimage.png?alt=media\&token=57f65a7c-54ac-4f14-b882-0e9e5e9bc648)

* Areas
  * Working Area (Not staged area) -> When ever any files are changed/modified
  * Staging Area -> We can add working area files to staging area using `git add -A` command
  * Committed Aread -> We can add all the files in staging area into committed area as a commit.&#x20;
* A folder can be turned into a **working directory** by having .git file in it. This can be done by using command `git init`
* Whenever we modify any file, that file will become untracked file. Meaning&#x20;

### Untracked files

When file initially gets **created** and **before adding it to staging area**, the file/files will be **untracked**

![](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fj7dSIBQ0aNZedtTU2ckD%2Fimage.png?alt=media\&token=11ec58bb-b16e-4795-91be-b00854b2e8f0)

### Staging area

![staging area](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F9p8nXgoG36f0W210BC8f%2Fimage.png?alt=media\&token=dc9799a1-9612-4788-99dc-d2ee9f28e5d0)

### Git status

`git status` gives the following information

* branch info
* Whether or what files are in working area (not yet in staging area) Or files in staging area (not yet committed)

![git status (files are in working area)](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FWZlapeAL4AZl1Rmpc5aE%2Fimage.png?alt=media\&token=2088cf01-668e-4623-a673-e65a0643cd75)

![git status (files are in staging area)](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FdBJqbPRfCZHu0jQiFJI3%2Fimage.png?alt=media\&token=2a15497f-080a-4cd5-923c-1943a08462fa)

### Git Log

git log gives the details of all the commits:

* Commit ID (unique Id for each commit)
* Head commit pointer (tells which commit is the head)
* Author of the commit
* Date of commit
* Commit messge

![git log](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FQpwEXI0LI9MqQpyOo6ox%2Fimage.png?alt=media\&token=22878110-e900-4876-9d49-6099ec6d7f4e)

![git log command](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FkwDFC5h7LFioxkNQnNIE%2Fimage.png?alt=media\&token=ae2e5907-10df-4eb3-87b6-61b3b2fa6cd7)

## Branches and Commits

* Branch is a **unique set of code changes** that holds commits
* Default branch is **master**

![branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FUtkIxLmoDCaUab9M0L3a%2Fimage.png?alt=media\&token=4a794dee-a98c-4b05-a451-dc8774527f75)

* **If we want to add some features**, we might not want to spoil the code of the existing branch by adding unwanted commits. Adding unwanted commits and then reverting back will be a big headache. In some cases we might not have access to add commits to the master branch (for example open source projects). In such case we **better create a replica of the master** or some other branch we would like to add our commits to. This replica is called a **sub-branch or feature branch** which we can name anything. To this branch, we start adding commits and then once our code works properly we can **merge it back to master** branch/ to branch which we branched out from.
* This process is called merging branches

![Landing page branch branched out from master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FSpiSHTQyZy6Kclv134sR%2Fimage.png?alt=media\&token=b9d6ed8e-f8b9-4d65-990c-f6e980006757)

### Check current branch

The number of branches in our project and the current branch we are working with can be checked using&#x20;

```
git branch
```

![we have a single branch at the moment and that's the current branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FOEClWgFABTSF2ciLqijQ%2Fimage.png?alt=media\&token=5db05e35-3860-474d-b753-4b36d9330a2d)

### Create new branches

**First Way**

* To **create a new branch** from **master** and **still be in the master branch**

```
// currently in master branch

git branch second-branch
```

To **switch** to second-branch

```
git checkout second-branch
```

![switch branch (method 1) - old way](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F6ZtG6jnsSNCgTT7dvjJn%2Fimage.png?alt=media\&token=23bb2172-67b9-4586-ad53-5c895b957acd)

**Second Way**

In the above process, we first create a branch with git branch second-branch and then switch to that branch with git checkout second-branch. But we can do both of these Creating and Swtiching in one single command.

```
// Be in the branch you would like to branch out from, like in above case

git branch -b second-branch
```

{% hint style="info" %}
Note : The above command can create two branches with same name, so I suggest you to run this command if the branch with that name doesn't exist
{% endhint %}

{% hint style="warning" %}
Note : In git world, **checkout** means switching the existing branches or creating a new branch and then switching to it.
{% endhint %}

**Third Way (Git version 2.23+)**

The word checkout can be confusing so git introduced new word switch to switch branches and create new branches and then switch to them.

```
// To switch to some other existing branch

git switch branch-name

// To create a new branch and then swtich to that branch

git switch -c branch-name

// the flag -c refres to create
```

![git switch to existing branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FXUdxy85QXjpwOqkJswKn%2Fimage.png?alt=media\&token=cf615b00-8b0f-4c81-a1fd-fe5680761469)

![git switch to a new branch (first create and then switch)](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F7zjSNBwVNuBkQcDwdSiO%2Fimage.png?alt=media\&token=62e8755b-cc3f-44cc-938c-ed634d6d06fe)

### Merge Branches

Based on above commands we now know how to create a branch from one branch. Let's say we did that and added some changes to the second-branch. And now, we need to **merge the second-branch into the master branch**.&#x20;

Let's say I need to merge second branch into master branch. The source is second-branch and the destination is master branch. I need to be in the destination to receive the source.&#x20;

Meaning, I need to be located in the master branch inroder to merge second-branch into master

![merge from second-branch to master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F1zAnFmTD4L6whKnNlTI9%2Fimage.png?alt=media\&token=15ded5aa-59ff-42f3-96c9-d75e176c2eb4)

```
// Merge second-branch into master

git merge second-branch
```

### What is Head

![Head](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F5aLxt1uRHOyo5Vc0Jgpn%2Fimage.png?alt=media\&token=341980d2-4c86-4516-9719-bce6ecd041c5)

Head is the latest commit of a particular branch. Head points to the latest commit in a branch. That's the reason when we switch from one branch to other branch the head might change as the switched branch would have the latest commit as shown in the fig above.

In the below example, we created two branches from master

* branchOne
* branchTwo

We added two commits to branch two and one commit to branch one. Now, when we log, each branch shows different head as the heads are pointing to the latest commits of that particular branch.

![branchOne](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FNqsfxY2R15xS4XTiviHf%2Fimage.png?alt=media\&token=e8dbe7a2-8cc7-4db1-bc6d-ebaffac3fcc8)

![branchTwo](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FqoPS0qbZgfBFiOAzzvas%2Fimage.png?alt=media\&token=f8b0f50e-93e9-4544-95bc-ebdeeb4bf4ed)

### Checking out commits (Detached Head)

If we checkout branches, that means we are switching from one branch to another as explained above which inturn means we are pointing to the latest commit of that particular branch.

**But, can we checkout a particular commit? A commit could belong to multiple branches.**

Yes, we can checkout a particular commit. **Checking out a particular commit is called Detached Head**. We are detaching a commit and our **head points to that particular commit**, hence it's called detached head.&#x20;

When the head points to particular commit then this means that head is not pointing to latest commit of any particular branch. The head is pointing to a commit that can be present in multiple branches. We can do lot of things detached heads like&#x20;

* Changing content of that commit and adding back to a particular branch
* Many more which we will explore later

Let's look at 3 stages.&#x20;

* Before checking out the commit
* Checking out the commit
* Switching back or checking out back to master

1. **Before Checking out the commit**

![current branch is master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F20hHaOJ851YoZ14pHnZh%2Fimage.png?alt=media\&token=002c33df-7877-4556-a7a2-c71919e4d5a7)

We are in the master branch. Let's see some of the commits in the master branch and then checkout a commit

![git log](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FjUucsn1PT0kIz80tnC5j%2Fimage.png?alt=media\&token=e7b8f59f-34b6-47f3-8acd-63dbea306c54)

**2. Checking out the commit**

Checking out this commit is done by command&#x20;

```
git checkout 3dc84fccd7dd31aab7f287794112a34e17939502
```

Now we have the **head pointing out to this commit** and **not any branch's latest commit**. That is why we have **detached head**.

![Detached head](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FIfy16aqfKVC7xksGdoG1%2Fimage.png?alt=media\&token=5f39396e-afe6-49ff-8ad2-8e869b8a8966)

Now, on doing git branch we get this commit (head current pointer) listed as a branch, but this is actually not a branch as we know.&#x20;

![Detached head is not a branch even though it shows like that](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FytXu1n5X0Zu2i0mSqXMO%2Fimage.png?alt=media\&token=15ef890c-0f5d-4795-a72a-a915a89a8bb2)

### Detached Head Vs Branch

Considering above explanation we know detached head is some random commit that might belong to one or more branches but that itself is not a branch. So what's the difference between a detached head and branch and why we need detatched head.

The first difference is "Detached head" is a commit that doesn't belong to a particular branch so it is not a part of branch. Where as branch is a commit that is linked to a particular branch.

**When we switch back to other branch, the detached head dissappears if we don't merge it into a branch**.&#x20;

**3. Switching back to master**

![switching back to master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fa7LkPGKBBcaZ8WPFl32R%2Fimage.png?alt=media\&token=ccaea4be-2b2f-47bd-801a-ffe8339a59ea)

{% hint style="warning" %}
Why we need detached heads? We can do many things with detached head. For example we can modify something in that commit and merge it back to some branch.&#x20;
{% endhint %}

![Making changes on detached head and adding commits to detached head and merging into master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FG2VveRboEwDPzBz3XinV%2Fimage.png?alt=media\&token=b2ee7530-bc86-4ca4-a72e-a3dd7cf3a930)

![Git log after meging the detached head (made as branch) into master branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fhw6Db10HT22oabGUViWw%2Fimage.png?alt=media\&token=470997d1-e461-40bd-a4ed-1ddd80424e3c)

## Deleting And Restoring Data

Let's see how to delete&#x20;

* Working directory files (part of previous commit)
* Unstage changes&#x20;
* Staged changes
* Latest commits
* Branches

### How staging area handles the files

Before we understand how we delete files let's see how staging area handles the files.&#x20;

```
// Files in staging area

git ls-files
```

The above command gives info about all files present in staging area. Meaning, everything that was a part of previous commit.&#x20;

### Delete Working directory (committed) files

Let's now say I delete a file from working directory (remember all the files were previously committed and all are in staging area now). Having said that, even though I delete a file from working directory, it would still be present in staging area.

![staging area files](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FimZ8tlJ35rho0lYi1MP5%2Fimage.png?alt=media\&token=0ffd4c23-9103-4eee-97a1-6fac54a3c105)

For next commit, we need to remove this file. For that we first need to delete this file from staging area. So once we delete the file from working directory like shown above, we need to add the changes of file removal in staging area like below.

![staging area removing file](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FUZcoBcfBpWjIQMQxpJKh%2Fimage.png?alt=media\&token=41e06c40-9f2f-4276-81bf-28f2c302a902)

{% hint style="success" %}
We know that whatever is in staging area will be committed for next commit if not already done. So to see what will be committed next, we need to see what files are in staging area.&#x20;

Staging area files --------> Next committable files

To see those files

```javascript
git ls-files
```

{% endhint %}

### Undo or Restore unstaged changes

{% hint style="info" %}
**Tracked file** - The file that is already a part of staging area. (add command used atleast once on this file)

**Untracked file** - The file that  is added newly but never added to staging area with add command
{% endhint %}

Let's say we have committed everything and now our staging area files is equal to committed files.  Let's now add some changes to an existing file.&#x20;

After some time, now, we want to get rid of those changes. Meaning, we need to get rid of the files that were not added to staging area.

![Unstaged content removal](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FgHqW9iFpBthqVn157r2n%2Fimage.png?alt=media\&token=e3c343f5-b605-4a34-9346-417ef0a973de)

How to get rid of changes made? In this case we need to restore back to a state where it should be exactly after committed. Meaning, we need to get rid of line number 5 which was added after committing.

![go back to staging area of this branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FNikMZPMi99s2YJNfErsD%2Fimage.png?alt=media\&token=6878825e-c14e-4dcd-a1e1-8baf37b8d818)

This line 5 will now be deleted with the command

```javascript
git checkout -- initial-commit.txt
```

What is the meaning of this command?

Well, we know checkout is used to switch branches. **When we switch to a branch, it means we get all the files in STAGING AREA OF THAT BRANCH into picture.**

So when we do `git checkout`, it means we are showing the staging area of a particular branch.

So the above command `git checkout -- initial-commit.txt` means that, show me the staging area of this branch only (--) for the file initial-commit.txt. That means what ever file content of `initial-commit.txt` is in staging, that will be the initial-commit.txt.&#x20;

In the above command -- is optional. So we can write

```
git checkout initial-commit.txt
```

Let's say we need to revert multiple files, then we can say

```
git checkout .
```

**From git 2.23+ version**

```
git restore .
```

![deleting unstaged changes](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F3GP2BLPJIrakf9dR7SyI%2Fimage.png?alt=media\&token=04fa12c6-6534-41c6-883a-9338118e1cdc)

**What if I need to delete a newly created file which is not yet staged (not yet added to staging )?**

Let's say I just created a file and not yet run add command. I need to delete that now.&#x20;

![Need to delete the unstaged (unadded) file](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F7l12CWo6GDM6MhfnZoCF%2Fimage.png?alt=media\&token=333735d5-cae9-42fc-a968-7f949d361434)

First list the files that need to be  deleted. Then you can delete them

```
git clean -dn
```

![Lists the files that need to be delted but won't delete](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FgwvGBIY2tsKU9IDhhTSW%2Fimage.png?alt=media\&token=f1f8aa8f-6a63-49b4-b8ec-cd0698516bd5)

The above command just lists the files that could be deleted which are untracked files.

To delete them use the command below.

```javascript
git clean -df
```

![remove untracked files](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F5IunDOhj08vRX5yhuH8f%2Fimage.png?alt=media\&token=0292ca0b-926f-49d4-84b4-2b45b2ed2b05)

### Undo or Restore Staged Changes

We saw how to undo unstaged changes (where if the content is modified but not added to staged area even once then we can simply checkout all the files in staging area to bring it to focus so that all the changes made will be lost).

But let's say I make some changes to a file and add it to staging area. Now, in this case how to revert back. We can not do like we did above because, above, we just brought staging area files into focus where staging area was clean. But in this case, the staging area got polluted as we added a file into staging area.&#x20;

If we think logically the solution would be

* First unpollute or restore staging area back to normal. How? The lastest commit is what the expected staging area to look like correct? So we can make the latest commit as our staging area. This is possible by command

```javascript
git reset filename // filename if not given, it will reset the entire staging area for all files
```

* Now latest commit is what we have in staging area. Meaning, the file changes are unstaged at this point. Now we can remove unstaged file as learned in our previous content above

```javascript
git checkout . // note that -A doesn't work here. . works
```

**1st way / old way** (less than git version 2.23) of **removing staged files**.

```javascript
git reset filename  OR git reset
git checkout .
```

**2nd way (git 2.23+)**

```javascript
git restore --staged filename 
git checkout .
```

### Deleting commits

`git reset` helps to not only reset the staging area (makes staging area equal to latest commit) but also helps in deleting the commits by resetting the head from latest commit to old commit.

We have different types of deleting the commits.

* soft reset
* normal reset
* hard reset

#### Soft reset

Undoing the commmit. It's like not doing commit at all. The general process we follow is&#x20;

**Creating a file + Adding files to staging area + Committing the files in staging area**

But in soft reset we just get rid of last part and it's undoing the last part. The files get back to staging area and the commit gets deleted

~~Committing a file~~ -> **File changes comes to staging area** -> File changes now in working directory

```
// To delete one commit

git reset --soft HEAD~1

// To delete two commits

git reset --soft HEAD~2
```

This can also be used to change or modify the commit message.

#### Normal reset

Undoing a commit + removing the changes from staging area. It looks like this

~~Committing a file~~ -> ~~File changes comes to staging area~~ -> **File changes now in working directory**

```
// To delete one commit. The file changes becomes as it was working area 
(not staging area)

 git reset HEAD~1 
```

#### Hard Reset

Undoing a commit + removing the changes from staging area + working directory file changes. Basically, we remove everything until last commit. So the working directory becomes equal to previous commit. It's like we never wrote any code after previous commit.

~~Committing a file~~ -> ~~File changes comes to staging area~~ -> ~~File changes now in working directory~~

```
// To delete the latest commit and make the working area like previous commit

git reset --hard HEAD~1
```

### Delete Branches

To delete a branch that is already merged into another branch

```
git branch -d branch-name

// to delete multiple which are already merged

git branch -d branch1, branch2, branch3
```

To delete a branch even though that is not merged (kind of force)

```
git branch -D branch-name

// to delete multiple branches

git branch -D branch1, branch2, branch3
```

## Git Stash

Let's say I did a commit. Now, if I check the status, everything will be clean in the working directory. Now I will introduce some code, but suddenly I want to save these local changes and see how the work space was before when I didn't yet start the code after the commit.&#x20;

One of the options to make the working directory equal to previous commit is by using the command `git checkout .` With this command I would get back my clean working directory like how it was after the commit and before starting to code locally but the biggest problem is I would lose the local changes which was not added to the staging yet.&#x20;

Git stash solves this problem. It makes our working directory clean and resets back the working directory to how it was after the commit and before starting the work locally + it saves the local changes made in stashed area.

Let's do these steps&#x20;

* Now the working directory is clean and nothing is changed to add to staging area
* Do some changes to file.txt

{% code title="file.txt" %}

```
Added this feature!
```

{% endcode %}

* Now I want to see the workspace how it was after the previous commit, but at the same time I don't want to lose this above change to file.txt. So I can stash here

```
git stash
```

* Now the file.txt has no content and the working directory is clean (nothing to be staged)
* Let's say I want to bring back this stash to working directory

```
git stash apply
```

* Let's add another feature to the file.txt

{% code title="file.txt" %}

```
Added this feature! // this was from stash 1

Added second feature! // this needs to be stashed now
```

{% endcode %}

* Let's stash this also

```
git stash
```

* Now we have two stash (1 with first line in file.txt and the lastest stash with both the lines in file.txt)
* Let's see all the stash

```
git stash list

// The output will look like this
stash@{0}: WIP on master: 213977a merging detached-head-to-master-branch
stash@{1}: WIP on master: 213977a merging detached-head-to-master-branch
stash@{2}: WIP on master: 213977a merging detached-head-to-master-branch
stash@{3}: WIP on master: 213977a merging detached-head-to-master-branch
```

* Note that you can't apply a stash when you are already in a stash. You either commit the current stash and then apply another stash OR you stash again and then apply the required stash.
* Now let's apply stash 3. Note that stash 0 is always the latest stash

```
git stash apply 3
```

* How to apply the latest stash and at the same time delete that stash

```
git stash pop <stash-number>
```

* How to delete a single stash

```
git stash drop <stash-number>
```

* How to delete all the stash

```
git stash clear
```

* How to add meaningful message to stash

```
// instead of git stash, use the below command

git stash push -m "<your message here>"
```

## &#x20;Merging Branches

Two types of merges

* Fast-forward merge&#x20;
* Non-fast-forward recursive merge

### Fast forward merge

The feature branch is branched out from master. We then don't add commits to master until  we merge back the feature.

![Fast forward merge](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FVKj1oxFok6rVgJeReSHZ%2Fimage.png?alt=media\&token=0304bae3-30e5-4508-a693-6f665afb11c2)

![Fast forward merge ](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FeSyLfyCQ5a4z29HMFs58%2Fimage.png?alt=media\&token=c2e1b2a7-bd08-4204-8aaa-b673251431f9)

#### Fast forward merge practical example

* Created two commits m1 and m2 in master branch

![master branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Ff5WsNzt3nZOhJZ1Th9s7%2Fimage.png?alt=media\&token=f1631133-0731-40c3-bcc7-c2a1adcb691d)

* Create a new branch called feature and switch to feature branch

![feature branch created from master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FV9FTeYQUoyF4vzLsWjsQ%2Fimage.png?alt=media\&token=663adf10-6624-4fb6-a03d-110af14d7962)

* Now let's switch back to master and **merge** **feature** into **master**

![merged feature into master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FsYWHQ1mgKk0UD3Jda1Cu%2Fimage.png?alt=media\&token=0c3bdb6f-d300-4f50-a265-f8c422242d5e)

![Merged back feature to master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FVCraB8Vi4QfRqgUIO17K%2Fimage.png?alt=media\&token=6c8d0a57-0f41-4106-82aa-bec8e33d916f)

The above stuff is explained in a digramatic way

![Fast foward merge](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FxC0E7tbdZr2Fn3uT1wA1%2Fimage.png?alt=media\&token=59b59f03-dd44-443f-afad-5d496c87117b)

#### Squash merge

Now you see, when we merge feature branch back to master, we get **all the commits of feature branch (f1 and f2 in this case) displayed in master.** **We might not want to know all the incremental changes happend in feature** and we need **all the commits of feature branch to be combined into one single commit in master when merged**.&#x20;

```
git merge --squash feature
```

**This squash flag gets the latest commit of feature branch and put it to staging area of master.** This let's you commit with your own message in master branch.

![squash combines f2 into staging area of master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FiFE1zmAp7fmFDecrL3j6%2Fimage.png?alt=media\&token=f16c85bd-c41f-4a1b-ae35-0418d1d20fc9)

f1+f2 will be present in f2 commit. Merging with squash will add f2 to staging area of master. We can then commit that as we need into master as a normal commit. This keeps the master branch clean.

![commit staging area to master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FSlyjv7AVLLHHrMY5oJZA%2Fimage.png?alt=media\&token=2235eaec-b8d1-4395-a337-88ffa3be61f0)

![squash merge](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FFPxWCWx6AZClNRZS7M3W%2Fimage.png?alt=media\&token=a5b68d1e-f82a-401c-b4df-743b554e8c1c)

![squash merge commit into master branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FsZjb2R9BmlBbsSZWJlOa%2Fimage.png?alt=media\&token=2c7042a4-8c49-42c3-85b3-b32705d659de)

### Non-fast-forward merge (Recursive merge)

This is generally used when, after creating a branch from master we would have additional commits in both master and the new branch.&#x20;

![recursive merge (non ff merge)  ](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FpKySqjtyGSx1z133Ogf8%2Fimage.png?alt=media\&token=ed1e9b6f-8ee3-47d2-8447-ac609e602b4d)

An additional commit is created in master after the merge of feature branch into master branch.

The latest merge commit holds all other commits below, and if you reset the head 1 time, then all the below commits will be gone.

```
//merge to master. This creates an extra commit
git merge --no-ff feature 
```

![no-ff merge](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FZzgzhLmcl70J2yj9HZXw%2Fimage.png?alt=media\&token=24bae015-de57-455e-aabf-f20e7f2d3bc1)

![no-ff creates an extra commit](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fz6jqnTrtxYtATg8dK2od%2Fimage.png?alt=media\&token=fd742efd-94fd-4220-9e54-f9ed760fcbe0)

![hard reset of 1 commit undos the feature branch merge by removing all commits related to feature branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Ff9d3MVQ2v3tE5Q9yJlGh%2Fimage.png?alt=media\&token=11caf0b6-c9ab-47d8-8624-37e06e008872)

![non-ff merge diagram](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FpDyGlDXuAYjfbKOdX9Yq%2Fimage.png?alt=media\&token=451ad379-2472-4d64-9553-f3bb444290c3)

![combined commit non-ff](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FevEHc8dfZRgPb3I4duw0%2Fimage.png?alt=media\&token=752e13ad-5a50-4cfc-9fa2-c410de060883)

## Git Rebase

We have seen two types of merge

* **Fast forward merge** - If we create a branch from master -> add commits to feature --> Merge back to master (No changes was done on master until merged back.
* **Non Fast forward merge** - If we create a branch from master -> add commits to master -> add commits to feature -> Merge back to master (There was a change in master after feature was created)

#### Now what is rebase?&#x20;

Let's consider Non-ff case where we have created a feature branch, then we create a new commit in master as well.&#x20;

We notice that we need this change done in master in our feature as well before we merge back feature into master. Then we can think of this rebase. In rebase we re-base (change the **base of commit of master to one commit ahead**) and then merge the **copy of commits (not the original commits - so you should be careful before using it)** from feature. This would be a fast-forward merge.

![rebase](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FpEqpY67FmC19l829JMjP%2Fimage.png?alt=media\&token=66c7b9e6-2bce-48ab-98ce-7eea85ee476b)

What actually happend here?

![rebase - behind the scenes](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F9cYjuNGqxrCAd5Z5kIGP%2Fimage.png?alt=media\&token=0c6599e9-295e-49f2-8329-db0a311d713d)

![Rebase](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FgchmYglIlEUrbl4SYuZP%2Fimage.png?alt=media\&token=ae5a8872-a3f4-46e9-bb88-d4ecb653ddd9)

![Rebase behind the scenes](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FG3qkIFczfXtJXsE5JS7W%2Fimage.png?alt=media\&token=0bdd1f31-daaa-46d3-b6bc-8e43882e214d)

Git will say "I want to base latest commits of feature branch on the latest commit of master branch."

#### Before Rebase, let's see the git log for both the branches

Master branch

![master branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FNn3ynGu1UOZ0cXekHbci%2Fimage.png?alt=media\&token=0d11ab01-10fb-4908-a7e6-36403bc2afde)

Feature Branch

![feature branch. Note we don't have m3 yet. ](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fh1ljJXoVPThCR6kqY8rr%2Fimage.png?alt=media\&token=50618d66-989b-41d2-b390-be80c4821cf0)

Note that, in feature branch, it branched out based on m2. Once we rebase, the feature branch would have rebased (will have m3 - latest commit of master) in feature branch. In the master, f1 will be the copy (hash will be different) of f1 feature.

Now, let's reabse

```
// I'm currently in feature branch

git rebase master

// this would create base as m3 in feature branch and f1 
// commit ID changes but content remains same
```

![rebased from feature](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F9e6viNMbaEJZ1I1VuPo1%2Fimage.png?alt=media\&token=af759ca6-2d06-42c7-8ed0-ad2dac5bc0d7)

Now let's merge feature into master. Since the latest commit in master (m3) is now the base commit in feature, the **merge type would be Fast-Foward merge**.&#x20;

![git merge (ff) after rebase](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FWTqSfHQT82V14rF9eUqI%2Fimage.png?alt=media\&token=1a1afa18-4531-4320-abc8-fa5f597477f4)

![When to rebase](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F2q99vuZjKlCw36fpBxxN%2Fimage.png?alt=media\&token=e71af286-b2f1-488f-81ae-75d51df90490)

![Caution with rebase](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F1sC0MQpqCTcmKQ7QYff1%2Fimage.png?alt=media\&token=6cbaccec-5176-4e7d-8a52-b61859be2d25)

## Git Cherry Pick

![differences](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F9SnQGRDEQpptYguYWyQH%2Fimage.png?alt=media\&token=c5390230-ae68-4f05-bc58-22d523ac86c0)

Let's say I am working on master and make a typo in a commit. My colleague will create a branch out of master and start working, but then notices the typo caused. He will first correct the typo in the feature branch and commit it (single commit used to fix the typo). Then he does additional commits on his feature.&#x20;

Later from master, I can cherry pick that particular commit that fixes the typo. Meaning, I can merge a single commit into my master which has the typo fixed. Note that, in cherry pick, the commit Id in master changes (it's a **copy of the commit and not the same commit**).

![typo in master](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FdLxFy4YryMxQbqsqWJ8Z%2Fimage.png?alt=media\&token=371ffd54-943c-4e30-81ca-d03bb1d77e1e)

![ready for cherry pick](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FiirlsZbbXJNuURqA7CJ4%2Fimage.png?alt=media\&token=13ca6469-93f3-4578-855d-ad605c7c1a55)

Now switch to master and type the command

```
git cherry-pick commit-id
```

![cherry pick](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F5jL1Bi4Mk2XLLxORnWI3%2Fimage.png?alt=media\&token=b060452b-91c3-44ca-a8a8-c688e7650f95)

## GITHUB

![Github content](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FGTNjy9X5s8MD0rNTuyAZ%2Fimage.png?alt=media\&token=ee8c9ba7-f579-4519-8007-e91bb934a1bf)

## Connecting Git and Github

![git and github connection](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FFsvJ4A4ViP1d4zNs3wXJ%2Fimage.png?alt=media\&token=1184bca5-f2e2-4a59-adf7-c17681a2ce86)

The below command

```
git remote add origin
```

is used to connect git and github (let git and github know about each other). But to bring the content of git to github, we use `git push` and for getting github content to local we use `git pull`

![push and pull](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FYHPSjmyATaSyuRDhr1YK%2Fimage.png?alt=media\&token=7772e738-4c18-4225-a2a7-82887a732c49)

#### Origin and branch

Origin - Remote repo URL we would like to access

master / main - Remote branch we would like to push to&#x20;

![origin and remote branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FA2WqrneK5sWBqK1CQdR1%2Fimage.png?alt=media\&token=b08b3749-cfe9-4b77-a2ae-b84ec90060a1)

## &#x20;How git and github gets connected - Under the hood

With git remote add origin command, we establish a connection between local and remote repository. This connection can't be established until we push something to remote repo. The process involves some more steps. &#x20;

![role of remote-tracking-branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FYYIAXpyjrZC8dAE1myYC%2Fimage.png?alt=media\&token=d3a0b64a-cbbd-42f9-8823-81e39e9048ab)

![git pull - git fetch and merge -> fetch updates the remote-tracking-branch with origin updates](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fq6ZPeigJ9hmhxTzXn10u%2Fimage.png?alt=media\&token=2a690d6f-0f19-4257-a315-a909880ee33e)

Command `git branch` gives local branches. But `git branch -a` gives an extra entry of remote-tracking-branch. Remote-tracking-branch as said, gets created when we first type `git push origin master` command.

![local and remote-tracking branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FwpQq0cTQk5pTXMhoVzIx%2Fimage.png?alt=media\&token=52f2463f-0e3f-418f-9a7d-66974a6ff748)

### Create branch locally and push to origin (remote)

Now that we know what is origin (remote), remote-tracking branch and so on, let's see &#x20;

* How to create a branch locally and push it to origin
* How to create a branch in origin(remotely) and then pull it to local

#### How to create a branch locally and push it to origin?

Let's create a feature branch locally and then push it to remote.

![git push origin feature in local creates remote branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FXHfRj430iDlEGuzgQrJZ%2Fimage.png?alt=media\&token=8ee165e5-26dc-44d3-a01e-5a641e4e085f)

![feature branch created in origin (remote)](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fd9O9qpQOmpsRhZzBo5vZ%2Fimage.png?alt=media\&token=a0eae405-ee9c-4a04-a164-52a8292b3543)

#### How to create a branch in origin(remotely) and then pull it to local ?

![branch created in origin](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FmKTiYljgaa6hhv8Q9DX1%2Fimage.png?alt=media\&token=2d4e24c9-eea7-46da-b484-be964174d21e)

To see remote branch

```
git ls-remote

// a network call will be made to display the remote branch info
```

![to see remote branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F5MWhu5dXppkTN6d06ABG%2Fimage.png?alt=media\&token=3a06605c-2957-4ae6-83ae-483ea866ed9e)

To have the remote changes updated locally (in this case we need to get feature-remote-branch to local

```
git fetch origin
```

![updated locally](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FP2aFL6O9fwRshmUBZ2ij%2Fimage.png?alt=media\&token=8476fc43-6e44-4a8b-9648-c6355a413e3a)

Now with `git fetch`, the Remote tracking branch (Read only remote branch in local) gets updated but let' s say you add another commit remotely and then fetch again with `git fetch,` the local branch (which is local version of same branch) would not get updated, but the git pull updates local branch as well. Let's understand how.

![local tracking branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FIDpMkWt4MBelV6bHlVj3%2Fimage.png?alt=media\&token=1ed7b693-1c0b-40db-b300-859a321a5334)

#### Local tracking branch and Remote tracking branch

![local and remote tracking branch](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fafx3SdlTjMNG7K0YdAm5%2Fimage.png?alt=media\&token=b49ceab2-ccf7-4c61-a7d3-d81a5e93a8d0)

**To just use git push and git pull**, without origin and branch name, **we need to be on local tracking branch**. To create local tracking branch below is the command. We don't need to worry about local and remote tracking branches but it's good to know how git and github gets connected using local and remote tracking branches. **The name of local tracking branch and remote tracking branch must be same**.

![git branch commands](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2Fq5xa1QGSxyENZlxpwXJZ%2Fimage.png?alt=media\&token=3aa45aed-27b8-4ca0-aeec-3c45ab04eff7)

![git branch commands](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2F8dEsZXUtoVMtURHjbN5s%2Fimage.png?alt=media\&token=b0394858-df1b-48ff-a3b9-8149d7049348)

When we do a **git clone**, the local-tracking-branch is also setup by default so that we can use **git pull and git push**.

## Upstream

Until now we manually created the local-tracking-branch and remote-tracking-branch which are what connecting the git and git-hub.&#x20;

By using -u (upstream) while pushing, the local-tracking-branch and remote-tracking-branch gets created automatically.

```
git push -u origin master
```

{% hint style="warning" %}
For deleting branch and commit on github please watch the video  82. Not making note of it as it's not so important
{% endhint %}

## Github Summary

![github summary](https://1944679227-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MVEiPUp08kYt33g51v7%2Fuploads%2FCsavJOSoLfJgaDB3r0pm%2Fimage.png?alt=media\&token=ff51c649-578d-4551-bb45-ff25fa543547)
