A good workflow leads to a usable, in-use and useful git tree.

Get up to date

  1. Update the master branch in my local environment:
git checkout master
git pull

As master is never changed in local, git pull will always do a fast-forward merge.

  1. Update a feature branch against the remote tracking branch:
git checkout feat1
git pull --rebase
  1. Update a feature branch against the origin/master branch:
git checkout feat1
git pull --rebase origin master

You could be tempted to git merge origin/master into your local branch creating a merge commit. This makes the graph more complex.

⚠️ Difference between merging origin/master into a feature branch and rebasing your feature branch on the top of origin/master

C8 only exists on origin/master so side1 and side2, two feature branches, need to be updated before being shared with your central repository and your teammates.

side1 is a local feature branch updated with git pull --rebase → no new commit are created.

side2 is a local feature branch updated with git pull → a merge commit C9 is created.

The git tree for side1 is more straight forward than the git tree for side2 which contains complicated branching links.

Screenshot_2021-03-24_at_17.42.00-1

Start a new branch

  1. From the local environment
git checkout master
git pull
git checkout -b feat1
  1. Push the change
git checkout feat1
git pull --rebase origin/master
git push

Clean your commits 📖

afterwards

For many reasons, you can decide to keep your commits in local and push them all at once at the end of your development. In this case you may need to rewrite some of your commit messages to clarify or clean them.

Learn to play with your bunch of commits to share beautiful branches to your teammates.

git checkout feat1
git fetch
git rebase -i origin/master

As you rewriting history, the push command could be rejected.

Untitled-3-1

--force-with-lease is a safer alternative than --force as it refuses to push changes if the remote branch contains commits from teammates. 📖

upstream

There is no need to clean your commits afterwards after using these commands:

  1. git add --patch 📖
git add -p ## select the changes to be added to the next commit
git commit -m "fix: Found this issue while working on this"
git add -p ## select the other changes not added to the previous commit
git commit -m "feat: New behavior added"
  1. git commit --amend --no-edit 📖
touch "Hello" >> README.md
git add README.md
git commit -m "doc: Introduce the project"
touch "Hello\n" >> README.md
git commit --amend --no-edit ## instead of `git commit -m "oops, new line"
  1. git commit --fixup 📖
touch "Hello" >> README.md
git add README.md
git commit -m "doc: Introduce the project" ## create commit 7736d8e
touch "How to contribute" >> CONTRIBUTING.md
git commit -m "doc: How to contribute"
touch "Hello\n" >> README.md
git commit --fixup 7736d8e ## create a special commit
git rebase -i --autosquash ## do what is expected

Rebase vs Merge Commit

True merge is done by git merge --no-ff while git merge --ff-only force a rebase instead. Using git merge without any flag make a fast-forward if possible (equivalent to git rebase or git merge --ff-only or create a merge commit instead (equivalent to git merge --no-ff).

The default commit message of a merge commit is standard : "Merge branch '<branch_name>'". This commit message is not very useful because it does not say anything that is not visible in the git tree.

*   58361b3 (HEAD -> master) feat: Add the Login functionnality
|\
| * f8c02aa (feat/Login) doc: Add some explanation for login capabilities
| * 7333496 feat: Add login button on home screen
| * d76776c feat: Add login behavior
|/
* aff31df initial commit
* f8c02aa (HEAD -> master, feat/Login) doc: Add some explanation for login capabilities
* 7333496 feat: Add login button on home screen
* d76776c feat: Add login behavior
* aff31df initial commit

In the former example with --no-ff the git tree shows explicitly the new functionality and the detailed work that has been done. When the second one, with --ff-only displays a linear history without grouping the commits around a feature.

A third version is possible with a well-known behavior from git platforms (github, gitlab, bitbucket) called squash and merge. The resulting git tree will be:

* 402b615 (HEAD -> master, feat/Login) feat: Add the Login functionnality
* aff31df initial commit

There are many commands to perform exactly the same action with git.
git pull --no-ff origin master is the same as git fetch origin && git merge --no-ff origin/master.
git pull --rebase origin master is the same as git fetch && git merge --ff-only origin/master and the same as git fetch && git rebase origin/master.