Chapters

Hide chapters

Advanced Git

Third Edition · Git 2.50 · Console

Section I: Advanced Git

Section 1: 7 chapters
Show chapters Hide chapters

8. Centralized Workflow
Written by Jawwad Ahmad

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

A centralized workflow is the simplest way to start with Git. With this workflow, you work directly on the main branch instead of in separate feature branches.

Creating branches in Git is extremely easy, so you should only skip creating branches when they would cause extra overhead that isn’t necessary.

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 the main branch.

When to use the centralized workflow

One of the primary 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 your main branch. 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 main              # 2: Switch back to main
git merge my-new-feature       # 3: Merge branch into main
git branch -d my-new-feature   # 4: Delete branch
git push main
# Write the code

git add . && git commit -m "Adding my new feature"
git push main

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
Zvabc raux rofg del-ipuccuvfeqs okdihdozi ob cosi ucdubpvok

3. When optimizing for development 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
Nonfnivubed Zarpwcac yd Zrikfweyy Baykcdos

4. When working on a new project

The need for expediency is often stronger when 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!
Dzuc neul faumxm woge! Qexx ymaz kb dxo 1zw!

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 main.

Rebase early and often

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

Avoid merge commits

At times, your local main branch may diverge from the remote origin/main branch. For example, when you have local commits that you haven’t pushed yet, and the remote origin/main 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/projects/starter/repos/alex/checklists # 1st Tab
cd path/to/projects/starter/repos/beth/checklists # 2nd Tab
cd path/to/projects/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
...
[user]
	name = Beth Blueberry
	email = beth@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 -> main) 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 -> main) A3: Added Checklists title within head
824f3c7 (origin/main) 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
4da1174 (HEAD -> main) B4: Added "Welcome to Checklists!" within body
ed17ce4 B3: Added "Checklists" heading within body
824f3c7 (origin/main) 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
Relationship between origin/main and Alex and Beth’s main branches
Wokevuunxbil culruiv ihohof/guin arf Iyaw ixd Memh’h wuex fwumdfaq

Pushing Beth’s commits to main

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

On branch main
Your branch is ahead of 'origin/main' by 2 commits.
...
4da1174 (HEAD -> main) B4: Added "Welcome to Checklists!" within body
ed17ce4 B3: Added "Checklists" heading within body
824f3c7 B2: Added empty head and body tags
...
Relationship between origin/main and local main branches after Beth’s push
Vijomuuzrhar bagmeuc aqinij/weoz osr bekaf puob scavwyoy awhal Nerg’z fizq

Pushing Alex’s commit to main

Switch to your alex/checklists tab and run git status:

On branch main
Your branch is ahead of 'origin/main' by 1 commit.
...
To ../../checklists.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to '../../checklists.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. If you want to integrate the remote changes,
hint: use 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Updates were rejected because the tip of your current branch is behind its remote counterpart.
If you want to integrate the remote changes, use 'git pull' before pushing again.
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
...
From ../../checklists
   824f3c7..4da1174  main       -> origin/main
On branch main
Your branch and 'origin/main' have diverged,
and have 1 and 2 different commits each, respectively.
  (use "git pull" if you want to integrate the remote branch with yours)
* 865202c (HEAD -> main) A3: Added Checklists title within head
| * 4da1174 (origin/main) B4: Added "Welcome to Checklists!" within body
| * 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
Hiqoag hikwixudsipiar iq yfi txazoauq wur jec --anevuqi --fsaqq --agv yobpujw

hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.

Creating a merge commit

When you use the --no-rebase option with git pull, it actually runs two two separate commands: git fetch and git merge origin/main.

git pull --no-rebase
Merge branch 'main' 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.

Aborting a merge commit

Take a look at the last line of the commit message template. It says:

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

Undoing a merge commit

Run git pull --no-rebase again to trigger the merge. When Vim opens, type :wq to accept the default message and commit the merge.

*   99f255d (HEAD -> main) Merge branch 'main' of ../../checklists
|\
| * 4da1174 (origin/main) B4: Added "Welcome to Checklists!" within body
| * 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

Rebasing the merge commit

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

git rebase origin/main
* 0c761be (HEAD -> main) A3: Added Checklists title within head
* 4da1174 (origin/main) B4: Added "Welcome to Checklists!" within body
* 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 --no-rebase is the combination of two separate commands: git fetch, and git merge origin/main.

Successfully rebased and updated refs/heads/main.
* c1f9be5 (HEAD -> main) A3: Added Checklists title within head
* 4da1174 (origin/main) B4: Added "Welcome to Checklists!" within body
* ed17ce4 B3: Added "Checklists" heading within body
...
git reset --hard 865202c

Setting up automatic rebase

You can also set up git pull so that it using --rebase by default. Recall that if you ran git pull and didn’t have a strategy configured to resolve divergent branches, you would have seen the following:

hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
git config pull.rebase true
git config pull.rebase true
Successfully rebased and updated refs/heads/main.
git push
...
To ../../checklists.git
   4da1174..c9266b9  main -> main

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 --no-rebase to avoid creating merge commits.
  • Set the pull.rebase option to true in your Git config to automatically rebase when pulling.
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.
© 2025 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now