Chapters

Hide chapters

Advanced Git

First Edition · Git 2.28 · Console

Section I: Advanced Git

Section 1: 7 chapters
Show chapters Hide chapters

8. Centralized Workflow
Written by Jawwad Ahmad

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

A centralized workflow is the simplest way to start with Git. With this system, you work directly on master instead of working in a branch and merging it with master when you’re done.

Creating branches in Git is extremely easy, so you should only skip them when they’re absolutely unnecessary.

In this chapter, you’ll learn about scenarios where the centralized workflow is a good fit. You’ll also learn how to handle common situations that arise when multiple developers are committing directly to master.

When to use the centralized workflow

One of the main reasons to first commit and push your code to a branch is to allow other developers to review your code before you push it to master. If the code doesn’t need to be reviewed, the overhead of creating and pushing a separate branch is unnecessary. That’s where the centralized workflow is a great fit.

Here are a few scenarios where a code review may not be necessary.

1. When working alone

If you’re the sole developer on a project, you don’t need the overhead of creating branches since there are no other developers to review your code.

git checkout -b my-new-feature # 1: Create and switch to branch
# Write the code
git add . && git commit -m "Adding my new feature"
git checkout master            # 2: Switch back to master
git merge my-new-feature       # 3: Merge branch into master
git branch -d my-new-feature   # 4: Delete branch
git push master
# Write the code
git add . && git commit -m "Adding my new feature"
git push master

2. When working on a small team

If you’re part of a small team where each team member has a specialized area of knowledge, a centralized workflow is a good choice. For example, if one developer works on backend code using one programming language and another works on front-end code in a different language, it’s not always useful or practical for those team members to review code outside of their area of expertise.

Small team with non-overlapping expertise or code ownership
Glirm geut begf tal-eciyhappuvz ivjibwalu ub fada iqxebsxeq

3. When optimizing for speed

Code reviews are a great way to improve the code’s quality before pushing it to the central repository, but every code review has some overhead.

Centralized Workflow vs Branching Workflow
Vomrzeyopir Kewtwmaq sz Qliblbobm Qunpzfic

4. When working on a new project

The need for expediency is often stronger when you’re working on a new project with tight deadlines. In this case, the inconvenience of waiting for a code review may be especially high.

          Drop dead launch date! Must ship by the 8th!
Rbum xior tootds hoka! Wagq sman mw lpu 3vb!

Centralized workflow best practices

Here are some best practices you can adopt to make using the centralized workflow easier. These are especially important when working in teams where multiple developers are committing to master.

Rebase early and often

When using the centralized workflow in a team, you often have to rebase before pushing to master to avoid merge commits.

Undo accidental merge commits

At times, your local master branch may diverge from the remote origin/master branch. For example, when you have local commits that you haven’t pushed yet, and the remote origin/master has newer commits pushed by others.

Getting started

To simulate working on a team, you’ll play the role of two developers, Alex and Beth!

starter
└── repos
    ├── alex
    │   └── checklists
    ├── beth
    │   └── checklists
    └── checklists.git
cd path/to/starter/repos/alex/checklists # 1st Tab
cd path/to/starter/repos/beth/checklists # 2nd Tab
cd path/to/starter/repos/checklists.git  # 3rd Tab
git config --get remote.origin.url # Note: The --get is optional
../../checklists.git
cat .git/config
...
[user]
	name = Alex Appleseed
	email = alex@example.com

State of the project

The remote origin repository, checklists.git, contains four commits, which we’ll refer to as A1, B1, A2 and B2 instead of with their commit hashes. Alex’s and Beth’s projects also have local commits that have not yet been pushed to the remote. Alex has one additional commit, A3, and Beth has two, B3 and B4.

824f3c7 (HEAD -> master) B2: Added empty head and body tags
3a9e970 A2: Added empty html tags
b7c58f4 B1: Added index.html with <!DOCTYPE html> tag
a04ae7f A1: Initial Commit: Added LICENSE and README.md
865202c (HEAD -> master) A3: Added Checklists title within head
824f3c7 (origin/master, origin/HEAD) B2: Added empty head and...
3a9e970 A2: Added empty html tags
b7c58f4 B1: Added index.html with <!DOCTYPE html> tag
a04ae7f A1: Initial Commit: Added LICENSE and README.md
4da1174 (HEAD -> master) B4: Added "Welcome to Checklists!" w...
ed17ce4 B3: Added "Checklists" heading within body
824f3c7 (origin/master, origin/HEAD) B2: Added empty head and...
3a9e970 A2: Added empty html tags
b7c58f4 B1: Added index.html with <!DOCTYPE html> tag
a04ae7f A1: Initial Commit: Added LICENSE and README.md
Relationship between origin/master and Alex and Beth’s master branches
Fazuxaejdvom gepyiov ofawoz/divdir ogh Owad ojt Meqg’s bewsex fmikgjap

Pushing Beth’s commits to master

Switch to beth/checklists in your terminal and run git status. It should show the following to verify that it’s ahead of origin/master by two commits:

On branch master
Your branch is ahead of 'origin/master' by 2 commits.
...
4da1174 (HEAD -> master) B4: Added "Welcome to Checklists!" w...
ed17ce4 B3: Added "Checklists" heading within body
824f3c7 B2: Added empty head and body tags
...
Relationship between origin/master and local master branches after Beth’s push
Pihuyaavkkos kosfaal aretod/songeq obj xedel rocgix txuhqkoz agdeq Nolk’s likl

Pushing Alex’s commit to master

Switch to alex/checklists and run git status:

On branch master
Your branch is ahead of 'origin/master' by 1 commit.
...
To ../../checklists.git
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to '../../checklists.git'
hint: Updates were rejected because the remote contains work
hint: that you do not have locally. This is usually caused by
hint: another repository pushing to the same ref. You may want
hint: to first integrate the remote changes (e.g.,
hint: 'git pull ...') before pushing again.
...
Updates were rejected because the remote contains work that you
do not have locally.
This is usually caused by another repository pushing to the same
ref.
You may want to first integrate the remote changes (e.g., 'git
pull ...') before pushing again.
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
...
On branch master
Your branch and 'origin/master' have diverged,
and have 1 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)
* 865202c (HEAD -> master) A3: Added Checklists title within ...
| * 4da1174 (origin/master, origin/HEAD) B4: Added "Welcome t...
| * ed17ce4 B3: Added "Checklists" heading within body
|/
* 824f3c7 B2: Added empty head and body tags
* 3a9e970 A2: Added empty html tags
* b7c58f4 B1: Added index.html with <!DOCTYPE html> tag
* a04ae7f A1: Initial Commit: Added LICENSE and README.md
Visual representation of the previous git log --oneline --graph --all command
Tigoun dezrebezdevuot up lfe gwujaaen bir qik --onivabi --tzozm --uhv hemjitz

Undoing a merge commit

Since Alex’s master branch has diverged from origin/master, running a git pull will result in a merge commit.

1. Abort the merge commit

The easiest way to prevent a merge commit is to short-circuit the process by leaving the commit message empty.

Merge branch 'master' of ../../checklists
# Please enter a commit message to explain why this merge is
# necessary, especially if it merges an updated upstream into
# a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message
# aborts the commit.
Lines starting with '#' will be ignored, and an empty message
aborts the commit.
Auto-merging index.html
error: Empty commit message.
Not committing merge; use 'git commit' to complete the merge.
...
All conflicts fixed but you are still merging.
...
git merge --abort

2. Hard reset to ORIG_HEAD

So what can you do if you accidentally created the merge commit? As long as you haven’t pushed it yet, you can reset your branch to its original commit hash before the merge.

*   fc15106 (HEAD -> master) Merge branch 'master' of ../../c...
|\
| * 4da1174 (origin/master, origin/HEAD) B4: Added "Welcome t...
| * ed17ce4 B3: Added "Checklists" heading within body
* | 865202c A3: Added Checklists title within head
|/
* 824f3c7 B2: Added empty head and body tags
* 3a9e970 A2: Added empty html tags
* b7c58f4 B1: Added index.html with <!DOCTYPE html> tag
* a04ae7f A1: Initial Commit: Added LICENSE and README.md

git rev-parse ORIG_HEAD
cat .git/ORIG_HEAD
865202c4bc2a12cc2fbb94f5980b00457d270113
git reset --hard ORIG_HEAD
HEAD is now at 865202c A3: Added Checklists title within head

3. Rebase the merge commit

Another strategy you can adopt is to rebase the merge commit onto origin/master. This applies A3 and the merge commit on top of B4. Since origin/master already has B3 and B4, i.e., the contents of the merge commit, this removes the merge commit entirely.

git rebase origin/master
* 7988360 (HEAD -> master) A3: Added Checklists title within ...
* 4da1174 (origin/master, origin/HEAD) B4: Added "Welcome to ...
* ed17ce4 B3: Added "Checklists" heading within body
* 824f3c7 B2: Added empty head and body tags
* 3a9e970 A2: Added empty html tags
* b7c58f4 B1: Added index.html with <!DOCTYPE html> tag
* a04ae7f A1: Initial Commit: Added LICENSE and README.md

git reset --hard 865202c

Using git pull –rebase

You previously learned that git pull is the combination of two separate commands: git fetch, and git merge origin/master.

First, rewinding head to replay your work on top of it...
Applying: A3: Added Checklists title within head
* 4742353 (HEAD -> master) A3: Added Checklists title within ...
* 4da1174 (origin/master, origin/HEAD) B4: Added "Welcome to ...
* ed17ce4 B3: Added "Checklists" heading within body
...
git reset --hard 865202c

Setting up automatic rebase

You may occasionally forget that you have local commits on master before you run git pull, resulting in a merge commit. Of course, this is no longer a terrible issue since you now know how to abort and undo merge commits.

git config pull.rebase true
git push

Key points

  • The centralized workflow is a good fit when working alone or on small teams, when optimizing for speed or when working on a new, unpublished project.
  • You can still create branches for in-progress code or for ad-hoc code reviews.
  • Rebase frequently to incorporate upstream changes and resolve conflicts sooner.
  • Prefer git pull --rebase instead of git pull to avoid creating merge commits.
  • Set the pull.rebase option to true in your Git config to automatically rebase when pulling.
  • There are multiple ways to undo accidental merge commits as long as you haven’t pushed them to the remote repository.
Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a Kodeco Personal Plan.

Unlock now