git

Git is a popular and widely used version control system (DVCS). We create snapshots of our project called commits ๐Ÿ”. They are stored in branches ๐Ÿชต, which are quite similar to local copies of a project.

Git usually involves two sides:

  • the git clients ๐Ÿ‘ฒ: they work on the project...
  • the remote git server ๐Ÿ–ฅ: it's a hub to synchronize every client...

Where to learn?


Pick your software

Git clients ๐Ÿ‘ฒ

You can use the git command directly or rely on plugins or software.

Remote Git Server ๐Ÿ–ฅ

There are multiple remote Git servers that you can use for free, while you may also self-host your Git server.

  • GitHub โœ…: popular Git server by Microsoft
  • GitLab โœ…: popular alternative to GitHub
  • Gogs ๐Ÿค”: self-hosted Git server
  • Gitea ๐Ÿ‘ป: self-hosted Git server
  • Bitbucket ๐Ÿ‘ป: atlassian Git server

To improve collaboration, they usually provide many new features.


Authentication

When using Git with a remote server, we need to log in for some operations such as git clone, git pull, git push... You may use one of these to log in (the default one being the less convenient):

  • Login/Password authentication ๐Ÿ”‘ โ€” default
  • SSH key authentication ๐Ÿ”
  • Personal access tokens ๐ŸŽซ

SSH key authentication

Using an SSH key, you don't need to enter a username/password.

$ ssh-keygen -t ed25519 -C "email"
Press ENTER every time.
You should add a passphrase to protect your key.
If you did, to use your key, you will have to enter the passphrase.
$ cat ~/.ssh/id_rsa.pub
<copy the content>

Read your Git Server documentation to find out where you can add an SSH key. It's commonly in Settings > SSH Keys.

Once added, you'll have to use a new URL to clone repositories. You may edit an existing repository remote URL to use the SSH URL.

๐Ÿ‘‰ It's the most common password-less method.

GPG commit signature

You can set up GPG keys to sign your commits. Anyone knowing your email can usurp your identity; however, signing commits increases the likelihood that you were the one who created the commit.

Tip: increase the delay between passphrase prompts

You will need to write a passphrase almost every time you are committing, unless you provided your passphrase in the last 10 minutes. You can increase the time your passphrase is cached

# note the location of the file
# this is usually ~/.gnupg/gpg-agent.conf
$ gpg-agent --gpgconf-list | head -n1
# create the file, or edit it
# cached 8 hours
$ echo "max-cache-ttl 28800" >> ~/.gnupg/gpg-agent.conf
$ echo "default-cache-ttl 28800" >> ~/.gnupg/gpg-agent.conf
# reload
$ gpg-connect-agent reloadagent /bye

On GitHub, signed commits are tagged "verified" next to them:

Verified commit

Personal access tokens

A personal access token is a string that you can use in multiple commands (such as git clone) that acts like a login/password.

$ git clone https://oauth2:ACCESS_TOKEN@example.com/xxx.git  # GitLab
$ git clone https://username:ACCESS_TOKEN@github.com/xxx.git # GitHub
$ cd xxx && git pull # no authentication

๐Ÿ‘‰ Refer to your Git Server to create one. Commonly used in scripts.


Git workflow

Git creates a tree of commits which are the snapshots/saves of your project. All files in a Git project are either (schema):

  • Untracked ๐Ÿšฎ: these files won't be saved
  • Staged ๐Ÿ“ฆ: these changes will be in the next commit
  • Unmodified โœ…: there are no changes since the last commit
  • Modified ๐Ÿซง: a tracked file was modified but not staged

To track or stage a file, use git add.

To create a commit, use git commit.

To see the state of files within a project, use git status.

While you may use Git locally, we mostly use a remote Git server. To get started, you need to download the current version of the project.

To download a Git project, use git clone.

To update your local project with the remote one, use git pull.

To push to the remote server your commits, use git push.

๐Ÿ‘‰ All commands and their arguments are explained here.


๐Ÿ’ด Commits ๐Ÿ’ด

Each commit stores information about its changes relative to the previous commit. You can view commits like a timeline or a thread.

When we create a branch, we actually initiate a divergence in the timeline, effectively creating one more timeline.

The result looks like a tree, hence the name "branch."

To navigate to a commit, use git checkout.

To edit a commit, use git rebase.

To edit the tree (move commits/...), use git rebase.

Each commit is identified by a unique SHA1 value.

โžก๏ธ Example: 1ed803c298f6dbfdc95bba1db3322c0f0ed7b6a5.

There are many aliases to make SHA1 easier to use:

  • Last commit (of our branch): HEAD or @
  • Shortened SHA1: 1ed803c2
  • One commit before SHA1: 1ed803c2^
  • N commits before SHA1: 1ed803c2^N or 1ed803c2~N

You can also use predicates such as: xxx@{two month ago} or xxx@{2021-05-05} which will be replaced with the closest commit.


๐Ÿชต Branches ๐Ÿชต

When working on a project, it's common to create a copy of the project and work on it, for instance, to test implementing a feature. By doing that, we ensure we still have a working project ("just in case" ๐Ÿ˜…).

A branch ๐Ÿชต is like a (shallow) copy of your project. Git provides features to manage them, including support for merging them.

The default branch, which is the one you work on by default, is usually called main (new term, more neutral) or master (previous traditional term).

โžก๏ธ Each branch's name, such as main or feature-xxx, is actually a named commit pointing to the last commit of their timeline (=branch).

To manage branches, use git branch.

To navigate between branches, use git checkout.

To merge branches, use git merge.

To rebase before a merge (cleaner history), use git rebase.

๐Ÿ‘‰ Most commands and their arguments are explained here.


Git remotes

Remotes specify where and how the code is fetched and sent when using operations such as git push, git pull...

They are automatically set when closing a repository. For remote git servers, the remote is commonly called origin.

You can use remote/myBranch to use a branch from a specific remote, for instance, origin/main.

For manipulating remotes, use git remote (usage).


Other topics

๐Ÿ“ฆ .gitignore

A "git ignore" is a really useful file to avoid tracking big or sensitive files. Any file inside will be ignored by version control. You can:

The format is similar to other ignore files:

*.zip     # ignore every zip
!toto.zip # don't ignore toto.zip
data/     # ignore every folder called 'data'
data/*    # ignore everything inside folders called 'data'
/data     # ignore only the folder data in the root directory

โš ๏ธ It only applies to untracked files. A file that was staged once won't be ignored. You'll have to remove the file and commit first. The file will still be in the history, see git filter-branch.

๐ŸŒž Good commits

Commits must be atomic, meaning you shouldn't do more than one implementation per commit (ex: adding a small feature). The second concern is to properly name commits:

  • ๐Ÿ“ƒ Usually, we add a type before any message (build, docs, feat (=MINOR), fix (=PATCH), style, test, chore, ci, perf, refactor, revert, security, and deps), followed by : giving us: feat:/...
  • โœ๏ธThen, we add the commit message, with a short description
  • ๐Ÿ“ฆ We may then leave a blank line, and add a body further describing the commit, such as adding a list of changes, or labels such as Co-authored-by, Reviewed-by, Refs...

See Conventional Commits, commitlint, and 7 rules.
Example: Atom - Git commit messages or commitment.


๐Ÿ‘ป To-do ๐Ÿ‘ป

Stuff that I found, but never read/used yet.

  • git pull merge branch
  • merge fast-forward vs rebase
  • GitGraph.js
  • Git hooks (+husky) - git hook
  • Google repo tool