Git commands to get you through the day
Tags: git, basics, tutorial, beginners
Published: 2021-03-13 10:19:39

Since the start of the year, I've been running weekly workshops with [Paddy Morgan](https://github.com/paddymorgan84) at work. These have been fun sessions to run. Some have been chats, some demos etc.

However, this week we ran a "Git 101" workshop. Weirdly, this was the most attended workshop we have run, with around 50 engineers joining throughout the hour session.

This post covers what we ran through.

---

**Time allocation:** 60 minutes

This workshop will be a high level overview of the basic git commands you will use daily. It's an entry level workshop, so if you're comfortable with git on the CLI, this probably isn't for you.

- Cloning
- Fetching
- Pulling/Pushing
- Branching
- Logging
- Rebasing

If we have time (intermediate)

- Hooks
- Configuration (Global and repo level)

## Notes

> Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

[Source](https://git-scm.com)

## Disclaimer

There are different ways to achieve the same thing. Here are some cheat sheets:

- [Atlassian](https://www.atlassian.com/git/tutorials/atlassian-git-cheatsheet)
- [GitLab](https://about.gitlab.com/images/press/git-cheat-sheet.pdf)

## Cloning

Git is a distributed version control system, so doesn’t require a centralised server. You can clone from another machine on a network, GitHub, GitLab, or your own git server.

For this example, however, we will use GitHub.

`git clone https://github.com/benmatselby/dotfiles.git`

`git clone` gets the codebase from GitHub, in this instance, and keeps a copy on your machine. You have now “cloned” the repo.

How do you know where the original end point is?

`git remote show`

This will show you the `origin` remote in the first instance.

`git remote show origin`

This gives you all the details of the `origin` remote. What the URL is etc.

But, you can have many, many origins.

```shell
git remote add github https://github.com/benmatselby/dotfiles.git
git remote show
git remote show github
```

This adds another remote, called `github` that points to the same endpoint, in this example (which is contrived).

## Fetching

Git is a distributed version control system. So you have the full repo locally, but changes are being made elsewhere. You need to `fetch` those changes.

Benefits of this include being able to work "offline" and still commit code. You do not need an internet connection to commit code!

`git fetch origin`

This pulls the latest information from the `origin` remote. This includes branches, tags etc.

But,

`git fetch github`

Also fetches from the `github remote`.

## Pulling

So, we have cloned and fetched. Now we need to pull the code into your branch.

`git pull origin main`

This pulls the code from the `origin` remote, and the `main` branch. You can change both of these values to match your remote and your branch.

At this point, you are “up to date” with what is on the server, wherever that server is.

## Branching

You have a clone, you have the code, now you want to change it.

`git checkout -b workshop origin/main`

So `git checkout` is the command. `-b` is the option to create a branch. `workshop` is the name of the new branch. `origin/main` is what I am branching from. It can be from any remote, or branch. You can even create a branch from a local branch:

`git checkout -b workshop main`

## Committing

You're on your branch, you've made some changes, now you need to commit.

We have a few options here:

`git add .`

This can be risky, if you are not overly disciplined on file management, or working logically.

or

`git add [file] [file]`

This can be better as it allows you to pick the files to stage, ready for commit.

Both of these options have staged files ready to be committed.

How do you know what to commit?

- `git diff` shows you what is not staged, that has changed.
- `git diff --cached` shows you what has been staged ready for commit.
- `git diff` shows you the diff, without whitespace changes.

`git status`

This shows you what is and is not staged, and what will be committed.

Again, a couple of options:

`git commit -a`

Again, this can be risky, if not overly disciplined as it will commit all changes you have made. This is the equivalent of `git add .` mentioned above.

or

`git commit`

Other options:

- `git commit -n` Very naughty. The `-n` means naughty, I promise. This essentially ignores any local hooks.
- `git commit -m "This is my commit message"`

Soap box:

- [Logically atomic commits](https://benmatselby.dev/post/logical-commits/)
- Please be liberal in information in your commit history. It's the only thing that stays with us.

## Pushing

Committing code, does not make it available for everyone, since git is distributed. So, we need to push the changes

`git push origin workshop`

So `git push` is the command. `origin` is the location of the server we want to push to. `workshop` is the branch we are pushing to.

## Rebasing

So you now commit all day long, but at the end of the day, you want to make [logically atomic commits](https://benmatselby.dev/post/logical-commits/). This means you need to learn rebasing.

I always think of rebasing as "replaying your work over the top of the latest code changes on the branch".

But you can also do much more with an "interactive rebase".

Normal rebase:

`git rebase origin/main`

Interactive rebase:

`git rebase -i origin/main`

Interactive rebase provides you a menu of options, such as squashing, picking, editing, dropping.

## Configuration (Global and repo level)

`git config --list` will show you all your configuration items.

You can break that down

- `git config --list --local`
- `git config --list --global`

So to add config

`git config --add user.email engineer@gmail.com`

This sets configuration locally to the repo you are in, and overrides global configuration.

To unset configuration

`git config --unset-all user.email`

Or to add configuration globally

`git config --global --add user.email engineer@gmail.com`

You can also edit `~/.gitconfig` for global configuration, and `.git/config` for the local repo configuration.

Let's say you want to have version controlled git configuration, but you need different email addresses (e.g. one for work, one for home), you can set the following:

```ini
[include]
  path = ~/.gitconfig.local
```

The contents of `~/.gitconfig.local`:

```shell
[user]
  name = Ben Selby
  email = engineer@gmail.com
```

## Logging

Logging is what it is, but here are some useful commands:

- `git log` - Show the log.
- `git log --stat` - Shows the log and the files changed.
- `git log --stat -p` - Shows the log and the files changed, and the diff!
- `git log --graph` - Shows the log and graphs how the commits came in.
- `git log --oneline --decorate` - Shows the title of the commits, and curates tags/branches. This is why useful git commits are important.
- `git shortlog` - Commits by engineer.
- `git shortlog -ns` - Commit totals by engineer, in order.

## Hooks

The [book](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks).

Note that there are server and client side hooks. If you maintain your own git server, you can have both. If you use GitHub, you have "GitHub Actions" as the server hooks.

Normally, we deal with local hooks, which are stored in `.git/hooks`.

## Tidbits

- `master` is being moved away from. If you `git init` a new repo now, git explains this. GitHub is also moving away from `master` in favour of `main`.
  - This is a good thing.
- `git init` creates a new repo.
- `git show [commit]` will show you the contents of the commit.
- `git ls-files` will give you a list of files in git.
- `git reset --soft HEAD~1` will undo the last commit from your local history.
- `git checkout origin/main -- README.md` will checkout `README.md` by itself from the `origin/main` branch.
- `git add -i [file]` will allow you to selectively add changes within a given file, using a menu.

## See also

- [Squashing commits](https://benmatselby.dev/post/squashing-commits/)
- [Logically atomic commits](https://benmatselby.dev/post/logical-commits/)
- [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/)
- [Git Tools - Rewriting History](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)