Best practices for collaborative development
by Francesco AgnolettoVersion control systems offer many benefits to any project:
Git is an open source and distributed version control system created by Linus Torvalds in 2005.
Git's core design principles:
$ git remote -v
> origin git@github.com:Kornil/my-repo.git (fetch)
> origin git@github.com:Kornil/my-repo.git (push)
Git stores a local copy of remote branches.
Updating them does not impact your working branches.
$ git fetch -p
# origin/master is updated
# master is untouched
The extra -p will also prune stale remote-tracking branches.
We can also update our local references with git pull.
This will also update our local branch with the latest commits from the remote.
$ git pull -p
# origin/master is updated
# master is also updated
git pull can also be pointed at a different branch.
git pull origin master is a useful way to update a feature branch with the latest code from master.
The commit is Git's fundamental unit, it is unique and immutable.
Commits record 5 essential details:
A branch is a movable pointer to a specific commit.
It creates an independent line of development.
By nature, branches are very cheap to create
Establishing a consistent naming convention for branches is a good practice for collaborative development. It directly improves:
HEAD is a special pointer indicating the current commit where you are.
HEAD is a special pointer indicating the current commit where you are.
By default, HEAD always points at the latest commit of the current branch.
HEAD is a special pointer indicating the current commit where you are.
By default, HEAD always points at the latest commit of the current branch.
It can be manually detached to point at any commit.
HEAD is a special pointer indicating the current commit where you are.
By default, HEAD always points at the latest commit of the current branch.
It can be manually detached to point at any commit.
Never commit in a detached head.
You will lose your work.
The stash can be used to store uncommitted changes and clean up the working directory.
This allows to quickly switch between different branches without having to commit WIP code.
# Store uncommitted changes
$ git stash push -m "new route wip"
$ git stash list
> stash@{0}: On master: new route wip
# Retrieve previously stored changes and delete the stash
$ git stash pop stash@{0}
# Retrieve previously stored changes and keep the stash
$ git stash apply stash@{0}
There are a few strategies when working with git, each with its own advantages and disadvantages.
Each commit should have a single scope.
Each commit should have a single scope.
The commit title should be clear and concise, extra information can be displayed in the body.
Each commit should have a single scope.
The commit title should be clear and concise, extra information can be displayed in the body.
$ git commit -m "Add createDashboard button"
$ git commit -m "Fix #123" -m "Additional details here"
Each commit should have a single scope.
The commit title should be clear and concise, extra information can be displayed in the body.
$ git commit -m "Add createDashboard button"
$ git commit -m "Fix #123" -m "Additional details here"
git add -p or any modern code editor.
Each branch should contain a single feature or bugfix.
Each branch should contain a single feature or bugfix.
$ git checkout -b "feature/grid-drag-drop"
$ git checkout -b "refactor/grid-module-typescript"
$ git checkout -b "fix/issue-33"
Atomic commits and branches have many benefits:
Atomic commits and branches have many benefits:
Atomic commits and branches have many benefits:
Atomic commits and branches have many benefits:
Atomic commits and branches have many benefits:
You must never EVER destroy other peoples history. Once you've published your history in some public site, other people may be using it, and so now it's clearly not your private history any more.
— Linus Torvalds
The key distinctions between Local vs. Shared history:
The key distinctions between Local vs. Shared history:
The key distinctions between Local vs. Shared history:
Git history, especially once it's shared, should be treated as a public record.
The consequences of not preserving history:
The easiest and safest way to delete a commit.
It will generate a new commit opposite of the target commit, removing all its changes and recording it in git's history.
$ git revert commit_hash_to_delete
$ git log -2
commit new_commit_hash
author: me
date: now
revert "bad commit"
commit commit_hash_to_delete
author: me
date: now
bad commit
This should be only used on private branches, it will modify history.
In this example only the last commit is modified but HEAD can be moved to affect more commits.
# last commit is gone, its content is now in the staging area
$ git reset --soft HEAD~
# last commit is gone, its content is now in the working area
$ git reset HEAD~
# last commit is gone, its content is gone
$ git reset --hard HEAD~
This is a more "complete" command compared to reset, should be only used on private branches, it will modify history.
# will target the last 4 commits
$ git rebase -i HEAD~4
# will open a rebase editor
pick 1234 Add readme.md
pick 2345 Fix typo
pick 3456 Fix another typo
pick 4567 work in progress
pick 5678 Add deploy script
pick 6789 Add second deploy script
# rebase editor
pick 1234 Add readme.md
fixup 2345 Fix typo
drop 3456 Fix another typo
reword 4567 work in progress
pick 5678 Add deploy script
squash 6789 Add second deploy script
The main branch moves on while you work on a feature. Integrating these changes is vital to keep our work updated.
Your choice depends on your goal for the project's history.
Preserves historical context.
Keeps a record of when a branch was merged.
Best for maintaining an audit trail.
Maintains a linear history.
Creates a cleaner history, easier to read and navigate.
Best for local cleanup before sharing.
The resulting history is fundamentally different.
A pull request or merge request is a proposal to merge changes from one branch into another.
It is not a part of git.
The pull request is one of the core features that led the rise of platforms like GitHub, it improves some big pain points of git:
There are only a few commands we need to use git effectively.
$ git checkout master
$ git pull -p
$ git checkout -b feature/download-button
$ git add button.tsx
$ git commit -m "Add button"
$ git add button.test.ts
$ git commit -m "Add button tests" -m "Existence check and click functionality"
$ git push
# Special mentions
$ git log -3
$ git rebase -i HEAD~3
$ git revert commit-hash
$ git status
$ git cherry-pick commit-hash
$ git fetch -p
We don't use git for ourselves, but for our team. Every operation we do should reflect that, without ego.