##Installing Git
###Linux
On debian based systems
```bash
apt-get install git
```
Latest stable upstream git version
```bash
add-apt-repository ppa:git-core/ppa
apt update
apt install git
```
###Windows
Go to the following links:
- https://git-scm.com/download/win
- https://gitforwindows.org/
Launch exe file.
To check version or existance of the git in system
```bash
git --version
```
Check global settings
```bash
git config --list
```
To start working with git we need to set several global variables
```bash
git config --global user.name "your_name"
git config --global user.email "your_email"
```
To get the manual for the command
```bash
git help command
git command --help
```
To create a repository and start tracking files got to the directory you want to track and use next command
```bash
git init
```
To check the status of the tracked files
```bash
git status
```
###Working with remote
We can clone existing repository (remote or on the same machine)
```bash
git clone <url> <where_to_clone>
```
To get information about remote repositories
```bash
git remote
```
This command will show list of remote handles that have been specified. To show also the links of remote repositories use `-v` flag.
```bash
git remote -v
```
By default remote handle has name `origin`. It is done automaticaly by using `clone` command. But you can create local git repository manually by `git init` and add remote repository manually.
```bash
git remote add name-of-handle url
--- example ---
git remote add origin https://github.com/someproj
```
To get more information about remote repository
```bash
git remote show name-of-handle
--- example ---
git remote show origin
```
No we are able to download all new information from remote repository.
```bash
git fetch name-of-handle
--- example ---
git fetch origin
```
After it we will have all the branches from remote project. __Important to note that `fetch` command only downloads changes from remote repository. It does not merge with any of your local branches and does not make any changes to your local work__. When `clone` command is used git also set up your current branch to track the remote branch so you can use `pull` command.
```bash
git pull name-of-handle branch-name
--- example ---
git pull origin master
```
This command will download changes and merge remote branch with your local branch. If `clone` was used no additional moves required. Otherwise we need to set it up manually.
```bash
git branch -u name-of-remote-branch
--- example ---
git branch -u origin/master
```
Or if your local branch is not current branch
```bash
git branch -u name-of-remote-branch name-of-local-branch
--- example ---
git branch -u origin/master testbranch
```
Also we can checkout remote branch. After it local branch will be created and set up for tracking remote branch.
```bash
git checkout name-of-remote-branch
--- example ---
git checkout origin/master
```
May be a problem when pulling info from remote branch due to unrelated histories. So use `--allow-unrelated-histories` flag when pulling.
```bash
git pull --allow-unrelated-histories
```
To rename remote repository
```bash
git remote rename current-name new-name
--- example ---
git remote rename origin pb
```
If you want to stop tracking remote repository
```bash
git remote remove name-of-handle
--- example ---
git remote remove origin
```
This command will fetch changes from remote repository for specified branch and merge it with local branch.
##Tracking files
If we dont want some files to be tracked we can create special file with the name of `.gitignore`. Here we can specify filenames, folder names, file extenstions that we dont want to track. `.gitignore` file has to exist near `.git` folder.
```bash
touch .gitignore
echo *.pyc >> .gitignore
```
Now files with extension *.pyc are ignored by git
To record changes in the file
```bash
git add filename
```
If we now check the status
```bash
git status
```
Added file will be marked with green color. This means this file is in `staging` area. Also there are several ways of using `git add` command.
[Image Name 1]:https://secretnotes.space/articleimage?id=157
![Image Name 1]
##Git add specifics
First flag is `-A` or `--all`. This flag will stage all changes made in entire working tree (deleted files, modified files,created files in current, upper and subdirectories except those files and folders specified in `.gitignore` file). Even if u run `git add -A` from the subdirectory entire working tree will be staged despite the fact that some files or folders were upper in the path.
```bash
git add -A
git add --all
```
Also it can be used with argument. For example if we want to stage only one folder
```bash
git add -A folder/
git add --all folder/
```
`git add -A` or `git add --all` is a default behaviour for the `git add` command. So we can it can be used next way
```bash
git add file
git add folder/
--- for example ---
git add main.py
git add src/
```
There is a flag `--no-all` or `--ignore-removal` that does not track deleted files.This command stages created files, modified files but no deleted files.
```bash
git add --no-all folder/
git add --ignore-removal folder/
```
Another flag is `-u` or `--update`. With the help of this flag git stages modified and deleted files for the whole working tree but no untracked files (new files)
```bash
git add -u
git add --update
```
Without argument this command will work for the whole working tree. Or we can specify folder as argument.
```bash
git add -u folder/
git add --update folder/
```
As the argument we can specify `.`. This will work only for current directory. It does not work for the whole working tree. It is similar to calling `git add -A` as long as you are in the top directory. But if you are in the subdirectory __git will not stage files in the upper direcotries__.
One more possible argument is `*`. It is a shell command. If we specify it as a git add argument git will stage all files in the current directory and subdirectories except deleted (not allways) and hidden files. Also git will not stage files in the upper directories.
```bash
git add *
git add * folder/
```
To remove file from staging area we can use `reset` command
```bash
git reset file
```
If it is used without arguments git will remove all files from staging area.
```bash
git reset
```
If files are in the staging area they can be commited
```bash
git commit -m "Some comment"
```
To check the history of commits
```bash
git log
```
To see what files were changed in latest commit
```bash
git log --stat
```
For the each commit we can see commit hash, branch, author, date and message.
##Branches
To list all branches (including remote)
```bash
git branch -a
```
To create branch
```bash
git branch name-of-the-branch
```
To list all local branches
```bash
git branch
```
To change current branch
```bash
git checkout name-of-the-branch
```
If we make changes in other branch it has no effect on the main (master) branch. We can push it to the remote repository but remote repository may not have branch that we have created. To create new branch in the remote repo
```bash
git push -u origin name-of-the-new-branch
```
After this command branch will be created in the remote repo.
Sooner or later branches are merged with each other, ussually side branch are merged with main. To do this we have to swith to the main branch (usually master branch)
```bash
git checkout master
```
With the help of next command we can check all branches that were merged into the branch we are currently on.
```bash
git branch --merged
```
Then merge with created branch
```bash
git merge name-of-the-other-branch
```
If there are no conflicts merge will run successfully. Now we can push changes from master branch to remote repository.
```bash
git push origin master
```
__It is a good practise to to `git pull` before pushing changes to remote repository. Someone could do changes to the repository when you was working on your part__.
Now after changes from side branch were merged with main branch we dont need the side branch. We can delete it.
```bash
git branch -d name-of-the-branch
```
To delete remote branch
```bash
git push origin --delete name-of-the-branch
```
To see what have changed in files from the last commit
```bash
git diff
```
##Git commit specifics
As was mentioned before to commit changes they have to be in staging area. We can check it with `git status`. To commit changes `git commit` is used
```bash
git commit -m "Comment"
```
If mistake was made in latest commit message we can fix it without undoing latest commit.
```bash
git commit --amend -m "New Message"
```
If we forgot to add some file to the staging area and commited it we are still able to add files we need in the latest commit.
```bash
git add file-or-files-we-need
```
Now use `git commit` with `--amend` flag
```bash
git commit --amend
```
Files that we added to staging area will be commited to the latest commit without creating a new one. `--amend` __flag rewrites the histroy of git commits__. It may not be the best idea if several people are working with one remote repository.
If we want to undo some changes in one of the commits without changing git history we can use `revert` command. To do this we need to know commit hash which we can find out with the help of `git log`.
```bash
git revert hash-of-the-commit
```
It will create a new commit that fully cancels another commit and everyone will be able to pull it. `revert` __does not change git commit history__.
If we made changes and commited them to the wrong branch we can use `git cherry-pick` to create new commits based on other commits that exist in other branch. To create new commit based on other we need to know hash of the commit. To find out it we can use `git log` command. After getting hash of the commit change the branch.
```bash
git branch branch-we-need
```
Now create a new commit based on original
```bash
git cherry-pick hash-of-the-commit
```
After running this command new commit will be created and added to git history. Files also will be changed. Original commit on the other branch will not disappear so we can reset that branch to the state we need.
##Git reset specifics
There are 3 types of reset:
- Soft
- Mixed (default)
- Hard
__Soft__ - Resets all tracked files to the staging area of specified commit.
```bash
git reset --soft hash-of-the-commit
```
Tracked files are in staging area (Green) but not yet commited. We are ready to make commit.
__Mixed (default)__ - Resets all tracked files to the working directory of specified commit.
```bash
git reset --mixed hash-of-the-commit
--- or ---
git reset hash-of-the-commit
```
Tracked files are in working directory (Red) but not yet commited. In order to make commit we need to add it and then commit.
__Hard__ - Resets all tracked files to the specified commit. File content is also changed. This command reverts all the tracked files but it does not touch untracked files.
```bash
git reset --hard hash-of-the-commit
```
Now don\`t have changes in working directory. Files are in the same state as in latest commit.
To get rid of untracked files
```bash
git clean -df
```
We can use `git reset` without arguments.
```bash
git reset --soft
--- or ---
git reset --mixed
--- or ---
git reset
--- or ---
git reset --hard
```
In this case git will reset all files to the latest commit.
We can also provide `git reset` with filepath argument. In these case `--soft` and `--hard` flags will not work. Only `--mixed` flag will work with filepath and because it is default we have no need to provide it.
```bash
git reset --mixed filepath
--- or ---
git reset filepath
```
This command will do oposite to adding file. File that was added before will be moved from staging area to the working directory (In git status file will change color from green to red) but content of the file will not be changed.
Also we can provide a folder name as an argument
```bash
git reset --mixed folder
--- or ---
git reset folder
--- or current folder ---
git reset .
--- or ---
git reset --mixed .
```
In this case operation will be done with files in folder.
Using `--soft` flag with reset command on the filepath or folder has no point because it reverts files from commited state to the staging area where we usually call `reset` command.
But if we want to make full reset on the file or files in some folder with changing its content back we can\`t use `git reset --hard filepath-or-folder`. Analogue to this command is
```bash
git checkout HEAD filepath-or-folder-name
--- or ---
git checkout HEAD -- filepath-or-folder-name
```
This command will change the contents of the file to the state it was in the latest commit. `--` strings specifies that we work with file but not branch (in case we have a file in working directory with the same name as one of the branches).
If file was changed but was not added to staging area we can reset file with the help of next command.
```bash
git checkout filepath-or-folder-name
--- or ---
git checkout -- filepath-or-folder-name
```
File will be changed to the state of the latest staging area state. (Will work only if changes in git status are red).
##Git stash
Great for changes that you are not ready to commit. You can save changes in the specific area.
```bash
git stash save "comment"
```
After saving them as stash all the changes will revert to the last commit. Stuff that we worked on will be in stash. To check stash
```bash
git stash list
```
To change files to the state they were in stash
```bash
git stash apply id
--- example ---
git stash apply stash@{0}
```
After changes were applied from stash we still have stash record in the list. To apply changes from latest stash record and delete it
```bash
git stash pop
```
To delete stash record without applying it
```bash
git stash drop id
--- example ---
git stash drop stash@{1}
```
To remove all stash saves
```bash
git stash clear
```
__Git stash works between branches. You can save stash in one branch and apply it in the other branch.__
##Git reflog
There is a story of git commands. To check it
```bash
git reflog
```
Here we can find hashes of operations in git. To revert to some point
```bash
git revert hash-of-operation
```
Now we are in deteched branch (HEAD). We can check it.
```bash
git branch
```
Our working directory is in state right after that commit was made. To save changes from HEAD to branch just create new branch and switch to it.
```bash
git branch new-branch
git checkout new-branch
```