# Git_Training

## Purpose

The Git Training session started with a lesson of basics on Git and collaborative development. You can find the presentation here: [ELIC_Git.pdf](http://www.climate.be:3000/TECLIM/Git_Training/src/master/Git_ELIC.pdf)

The second part of the Git Training consists on a hands on. The objectives are to show how to use:

- Git on the command line
- Gogs portal

We are going to do some exercises in a dummy project that you can find in this common Gogs repository: [project](http://www.climate.be:3000/TECLIM/Git_Training/src/master/project)

## Getting started

Prepare your environment for the first use of Git.

For instance:

```
git config --global user.name "My name"
git config --global user.email "my_mail@uclouvain.be"
git config --global color.ui auto
git config --global core.editor "vim"
git config --global push.default simple
```
Clone the Git_Training repository.

For instance:

```
git clone http://my_login@www.climate.be:3000/TECLIM/Git_Training.git
```
Or:

```
[ ! -f ~/.ssh/id_rsa.pub ] && ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub | xclip -sel clip
```
1. Go to http://www.climate.be:3000/user/settings/ssh, 
2. click on the 'Add Key' button, 
3. enter the Key Name you want, 
4. and finally do a 'CTRL-V' in Content. 

And now:
```
git clone ssh://git@www.climate.be:3022/TECLIM/Git_Training.git
```

## Tips and Tricks

#### How do I add an empty directory to a Git repository ?

 You can't. The design of the Git staging area only accounts for files (see below for the workaround).
 
#### And if I need an empty folder anyway ?

The solution to this Git empty directory problem is a simple workaround: just create a placeholder file in your empty Git directories to convince Git to put the empty directory into your Git repository. For instance:
 ```
touch .gitkeep
 ```
 
#### Git Auto-Completion

If you use the Bash shell, Git comes with a nice auto-completion script you can enable. Download it directly from the Git source code at https://github.com/git/git/blob/master/contrib/completion/git-completion.bash. Copy this file to your home directory, and add this to your ```.bashrc``` file:
 ```
source ~/git-completion.bash
 ```
 
#### git-config

Tell Git which whitespace problems it should recognize, namely any whitespace at the end of a line, as well as mixed spaces and tabs:

 ```
git config --global core.whitespace trailing-space,space-before-tab
 ```
 
#### gitignore

You don’t want to commit all your files into your repository. Things like temporary files, logs, configurations that are specific to a computer, files that are for testing only, private keys for code signing or files that can be easily regenerated all don’t belong in your repository. However, they will still show up whenever you type ```git status```, even though they are purely noise at that point.

For this reason you can specify what files you want Git to ignore in a special file called ```.gitignore```. Placed at the root of the repository, it contains glob patterns specifying all the files you want Git to ignore. Any file (and directory) matched by these globs won’t show up in git status, and if you try to add them via ```git add```, Git will refuse to do so (you can still add them by specifying the ```-f``` flag when adding).

For example, Rails 3 projects use the following ```.gitignore by``` default:
```
.bundle
db/*.sqlite3
log/*.log
tmp/
```

This tells Git to ignore the ```.bundle``` directory, all files ending in ```.sqlite3``` in the db directory, all the logs in ```log```, and everything in the ```tmp``` directory.

#### Using an external diff viewer

The built-in diff viewer is great most of the time, but sometimes you want to diff non-text files, or simply need a better visualization of what’s going on.

For this reason, Git allows you to specify external diff viewers. For instance:
```
git config diff.tool vimdiff
```
Then, when you want to diff, just use ```git difftool``` instead of ```git diff```. It will work as you expect.

## Tricky commands

Here are a few commands that you may not know yet, or that offer options you haven’t been aware of so far.

### git-stash

```git stash``` is something that can be incredibly handy. What it does is very simple: If you run ```git stash save```, it will take all the changes you have in your working directory and the index, and save them away, leaving you with a clean working directory. Once you’ve done what you wanted to do, you can restore your changes by running ```git stash pop```.

But it gets better: since ```git stash``` saves your changes in a commit, you can stash more than once, and you’ll get a nice list of commits with your stashed changes. ```git stash``` will also keep track of what branch you stashed your changes on, so you’ll know later on what stashed change exactly you want to restore.

```git stash list``` will list all the stashes you’ve saved away, ```git stash apply``` will apply the topmost stashed commit onto your working directory, ```git stash pop``` will also remove the stashed commit in addition to applying it. ```git stash clear``` throws away all your stashes, and ```git stash drop``` allows you to remove a single stash.

### git-rebase

```git rebase``` can be a very tricky command, although its purpose is very simple: Given a range of commits as well as a starting point, it will port the given commits onto that starting point, preserving the commits themselves, but also allowing you to keep a linear history (that is, no merge commit).

Most of the time you’ll give it just one ref: The branch you’ll want your current branch to rebase onto. ```git rebase``` then figures out where those two branches diverged, and use that as the beginning of the commit range. If you pass it a second argument, ```git rebase``` will first switch to that branch before porting your commits.

It also has one very useful flag: ```--interactive```. If you pass this flag, Git will launch your favorite editor with a list of all the commits it is going to rebase. All commits are prefixed with ```pick``` by default, but you can either drop commits entirely (just delete their line), reorder them to your liking, or ```edit``` if you’d like to edit or amend the commit (note that this also allows you to split commits), ```reword``` if you’d just like to change the commit message, and ```squash``` or ```fixup``` if you want to squash the commit with the previous one. ```fixup``` will reuse the previous commit’s message, while ```squash``` allows you to edit the new commit’s message.

The interactive mode is very useful when you’re working on some idea you’ve had, make a commit, and later on realize that it isn’t quite working out that way. You commit a fix, but the commit it fixes is already buried in other commits, so you can’t simply amend. ```git rebase --interactive``` allows you squash those two commits together and make it look like you never made the mistake in the first place.

### git-push

This is a command that you’re probably using often already, but it gained a few more useful options in recent versions:

- ```-u``` or ```--set-upstream```: When doing ```git push <repo> local-branch:remote-branch```, you can use ```-u``` to tell Git to set up ```remote-branch``` as the default upstream branch, so you’ll only need to do ```git push``` in future.
- ```--delete```: Instead of pushing the specified refs, it will instead delete them from the remote repository.

### git-reflog

Whenever an operation changes the tip of a branch, the Reflog mechanism records the old and new locations. ```git reflog``` allows you to access and manage this information.

This is very useful and potentially life saving after any command that (seemingly) changes the history of your repository, like ```git rebase``` or ```git filter-branch```. While these commands do indeed change commits, the old commits aren’t deleted, they are merely unreachable by normal means (This is also the reason why Git will occasionally run ```git gc``` on your repo). However, using the Reflog mechanism you can find out the SHA1’s of these commits, and restore them if you need to.

```git reflog``` lists all the recorded reflog information, and you can then specify any point in the reflog using the syntax ```head@{0}``` (where ```head``` is any kind of ref, and ```0``` to specify the very first reflog entry). For example, if you just did a rebase, but decided that you messed up somehow, you can restore your branch to its state before the rebase by using this command:

```
git reset head@{1}
```

## Contributors

- ELIC members [@pbarriat](http://www.climate.be:3000/pbarriat)

## References

- http://nuclearsquid.com/writings/git-tricks-tips-workflows/
- [BSC-CNS](https://gateway.bsc.es/dana-na/auth/url_default/welcome.cgi)

## License

This project is under the Creative Commons CC0 1.0 Universal License. See the [LICENSE](http://www.climate.be:3000/TECLIM/Git_Training/src/master/LICENSE) file for the full license text.
