KAHIBARO
Discord Login Register

3.11. Basic Git Workflow

Overview

In this chapter you will learn how to use Git in your daily work as a backend developer. You already know what Git is and how to install it from previous chapters. Here, we focus on the typical workflow you will repeat in almost every project.

We will walk step by step from cloning a repository to making changes, committing, pushing, pulling, and handling simple conflicts, with many concrete command examples.


The Life Cycle of a Change

A basic Git workflow for a backend project usually follows this pattern:

  1. Get the code on your machine:
    • git clone for a new project
    • or git pull to update an existing local copy
  2. Create a new branch for your work:
    • git checkout -b feature/...
  3. Work on files:
    • edit, add, delete, move
  4. See what changed:
    • git status
    • git diff
  5. Stage the changes you want to keep:
    • git add ...
  6. Commit with a clear message:
    • git commit -m "..."
  7. Push your branch to the remote:
    • git push origin your-branch
  8. Open a Pull Request / Merge Request on GitHub / GitLab
  9. After review, merge to main branch
  10. Update your local main / master:
    • git checkout main
    • git pull origin main

We will now go through each step in detail with examples.


Cloning a Repository

To work on a project that already exists on GitHub or GitLab, you clone it.

Example: Cloning from GitHub

Imagine you have a repository at:

https://github.com/example-user/todo-api.git

Open a terminal in the directory where you want the project folder:

bash
git clone https://github.com/example-user/todo-api.git

Git will create a new directory todo-api and download the full history.

Move into the project folder:

bash
cd todo-api

Check which branch you are on:

bash
git branch

Example output:

text
* main

This means your current branch is main.

Cloning with SSH

If you set up SSH keys, you might clone with SSH instead of HTTPS:

bash
git clone git@github.com:example-user/todo-api.git

For everyday workflow, cloning is done once per machine. After that you usually work with git pull and branches.


Checking Repository Status

Before and after changes, you should know what is going on in your repository. The main tool is:

bash
git status

Example Scenario

You just cloned the project:

bash
git status

Output:

text
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean

This means:

Now edit a file, for example app.py, and save it. Run:

bash
git status

Output:

text
On branch main
Your branch is up to date with 'origin/main'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
	modified:   app.py
no changes added to commit (use "git add" and/or "git commit -a")

Git tells you:

git status is safe and useful. Run it often.


Creating and Switching Branches

You rarely commit directly to main in team projects. Instead you create a new branch for each feature or bug fix.

Creating a Branch

Common naming patterns:

TypeExample Branch Name
Featurefeature/add-user-registration
Bug fixfix/login-timeout
Chorechore/update-dependencies
Experimentexperiment/new-cache-strategy

To create and switch to a new branch:

bash
git checkout -b feature/add-login-endpoint

This is shorthand for:

bash
git branch feature/add-login-endpoint
git checkout feature/add-login-endpoint

Check your branches:

bash
git branch

Example output:

text
  main
* feature/add-login-endpoint

The star shows your current branch.

Switching Between Branches

If you already created a branch:

bash
git checkout main
git checkout feature/add-login-endpoint

Git will refuse to switch branches if you have uncommitted changes that would be overwritten. In that case you must commit, stash, or discard those changes first.


Making and Inspecting Changes

Once you are on your feature branch, you change code as needed.

Editing Files

Example backend project structure:

text
todo-api/
  app/
    main.py
    models.py
    routes.py
  tests/
    test_tasks.py

You might:

After edits, run:

bash
git status

Example output:

text
On branch feature/add-login-endpoint
Changes not staged for commit:
	modified:   app/routes.py
	modified:   app/models.py
Untracked files:
	tests/test_auth.py

This tells you:

Viewing What Changed

To see the exact changes, use git diff.

Diff of all unstaged changes

bash
git diff

Example output:

diff
diff --git a/app/routes.py b/app/routes.py
index 1234567..89abcde 100644
--- a/app/routes.py
+++ b/app/routes.py
@@ -1,4 +1,9 @@
-from fastapi import APIRouter
+from fastapi import APIRouter, HTTPException
 router = APIRouter()
+@router.post("/login")
+def login(username: str, password: str):
+    # temporary implementation
+    return {"token": "fake-token"}

This shows additions starting with + and deletions starting with -.

Diff of a specific file

bash
git diff app/models.py

Use q to quit the diff viewer.


Staging Changes with `git add`

Before you commit, you must stage the changes you want to include.

Think of staging as selecting which changes go into the next snapshot.

Staging All Changes

To stage everything at once:

bash
git add .

or

bash
git add -A

This includes:

Use this only when you are sure that all changes belong together.

Staging Specific Files

Most of the time, it is better to be explicit.

bash
git add app/routes.py
git add tests/test_auth.py

Check status:

bash
git status

Example output:

text
On branch feature/add-login-endpoint
Changes to be committed:
	modified:   app/routes.py
	new file:   tests/test_auth.py
Changes not staged for commit:
	modified:   app/models.py

Now:

Staging Parts of a File (Optional but Useful)

Sometimes a file has unrelated changes that you want in separate commits.

You can stage interactively:

bash
git add -p app/routes.py

Git will show you each change chunk and ask if you want to stage it.

This is advanced but very useful for clean history.


Writing Commits

Once you have staged the correct changes, you create a commit. A commit is a snapshot with a message that explains why you changed the code.

Creating a Commit

bash
git commit -m "Add basic login endpoint and tests"

Check status again:

bash
git status

Example:

text
On branch feature/add-login-endpoint
Changes not staged for commit:
	modified:   app/models.py
nothing added to commit but untracked files present (use "git add" to track)

Your commit was created with the staged changes only.

The unstaged changes remain in your working directory.

Good Commit Messages

A clear commit message is very important for future you and for your teammates.

Some guidelines:

Examples:

Bad examples:

Important rule: Every commit should represent a logical, consistent change that can be explained in one sentence.

Multiple Commits for One Task

A full feature might need several commits, for example:

  1. Add User model and migration
  2. Implement login endpoint
  3. Add tests for login endpoint

Small, focused commits are easier to review and debug.


Viewing History and Details

To see your commit history:

bash
git log

Example output:

text
commit 7c9a1e6f0d0c3b6f2cb22b6dabae129a85f46899 (HEAD -> feature/add-login-endpoint)
Author: Your Name <you@example.com>
Date:   Thu Aug 22 14:37:10 2026 +0000
    Add login endpoint and auth tests
commit 5ab3c884a8da1e5910f8207b3c229e4b1a942c46 (origin/main, main)
Author: Teammate <teammate@example.com>
Date:   Wed Aug 21 10:12:01 2026 +0000
    Add task listing endpoint

Useful options:

To see changes of a specific commit:

bash
git show 7c9a1e6

You can copy the first few characters of the commit hash.


Pushing Your Work to the Remote

So far your commits exist only on your machine. To share them or create a Pull Request, you must push them to the remote repository.

First Push of a New Branch

If your branch does not exist on the remote yet:

bash
git push -u origin feature/add-login-endpoint

Explanation:

Next pushes on the same branch:

bash
git push

Pushing Updates

After more commits, just run:

bash
git push

If someone else or a CI system already changed the remote version of your branch, Git might refuse to push and tell you to pull first. We will cover this next.


Pulling Updates from Remote

To get changes from the remote into your local branch use:

bash
git pull

This is equivalent to:

bash
git fetch
git merge

Updating main

You will frequently update your local main branch:

bash
git checkout main
git pull origin main

This pulls the latest changes from origin/main into your local main.

Updating a Feature Branch

There are two common approaches:

  1. Merge latest main into your feature branch:
bash
   git checkout feature/add-login-endpoint
   git merge main
  1. Rebase your branch on top of main (more advanced, typically used in clean-history workflows). In beginner teams, a simple merge is usually enough and safer.

After pulling or merging, check status and run tests to ensure everything works.


Handling Simple Merge Conflicts

Sometimes git pull or git merge will result in a conflict. This happens when Git cannot automatically decide how to combine changes.

Example Conflict Scenario

bash
  git checkout main
  git pull origin main
  git checkout feature/add-login-endpoint
  git merge main

Git output:

text
Auto-merging app/routes.py
CONFLICT (content): Merge conflict in app/routes.py
Automatic merge failed; fix conflicts and then commit the result.

Conflict Markers

Open the file with the conflict:

python
@app.get("/tasks")
def list_tasks():
<<<<<<< HEAD
    return task_service.get_all_tasks()
=======
    return task_service.list_all()
>>>>>>> main

Explanation:

You must edit the file manually and choose or combine the correct version. For example:

python
@app.get("/tasks")
def list_tasks():
    # Use new unified service method
    return task_service.list_all()

When finished, remove all conflict markers.

Completing the Merge

After fixing all conflicts in all files:

bash
git add app/routes.py
git commit

Git will open an editor with a default merge commit message, or you can set it from the command line:

bash
git commit -m "Merge branch 'main' into feature/add-login-endpoint"

Then push:

bash
git push

You have now resolved the conflict and updated your branch.


Typical Workflow Example: Adding a New API Endpoint

To make it concrete, here is a full example of a simple daily workflow.

1. Update main

bash
git checkout main
git pull origin main

2. Create a feature branch

bash
git checkout -b feature/add-completed-filter

Goal: Add a completed query parameter to the tasks list endpoint.

3. Implement the change

Edit app/routes.py:

python
from fastapi import APIRouter, Query
@router.get("/tasks")
def list_tasks(completed: bool | None = Query(default=None)):
    return task_service.list_tasks(completed=completed)

Edit tests/test_tasks.py and add tests.

4. Check status and diff

bash
git status
git diff

Verify that only the intended changes are present.

5. Stage files

bash
git add app/routes.py tests/test_tasks.py

Check:

bash
git status

Output should list the two files under "Changes to be committed".

6. Commit

bash
git commit -m "Add completed filter to tasks list endpoint"

7. Push

bash
git push -u origin feature/add-completed-filter

8. Create Pull Request / Merge Request

9. Apply review changes (if any)

Reviewer asks you to adjust tests.

Edit files again, then:

bash
git status
git add tests/test_tasks.py
git commit -m "Adjust completed filter tests to check default value"
git push

The Pull Request updates automatically.

10. Merge and cleanup

After approval, merge the Pull Request through the web interface.

Locally:

bash
git checkout main
git pull origin main
git branch -d feature/add-completed-filter   # delete local branch
git push origin --delete feature/add-completed-filter   # optional, delete remote branch

Common Commands Quick Reference

TaskCommand example
Clone repositorygit clone URL
Check branch and statusgit status
List branchesgit branch
Create and switch to new branchgit checkout -b feature/name
Switch to existing branchgit checkout main
See changes (unstaged)git diff
See staged changesgit diff --cached
Stage specific filegit add path/to/file.py
Stage all changesgit add .
Commit with messagegit commit -m "Message"
Show historygit log or git log --oneline
Push new branchgit push -u origin feature/name
Push existing branchgit push
Pull changes into current branchgit pull
Merge another branch into currentgit merge main
Delete local branchgit branch -d feature/name
Delete remote branchgit push origin --delete feature/name

Key daily rules for Git workflow

  • Always work in a branch, not directly on main, in team projects.
  • Run git status and git diff before every commit.
  • Keep commits small and focused, with clear messages.
  • Pull and update main regularly, especially before starting new work.

By practicing this workflow repeatedly in your backend projects, Git will become a natural part of how you develop features and collaborate with others.

Views: 7

Comments

Please login to add a comment.

Don't have an account? Register now!