← ProgrammingBack to top

Git: Version control and team collaboration

Git is a distributed version control system for managing code history, branches, merges, and team collaboration.

1. Core model

Working Tree(workspace)
       ↓ git add
Index / Staging Area(Staging area)
       ↓ git commit
Local Repository(local repository)
       ↓ git push
Remote Repository(Remote repository)

Three key areas:

areafunction
Working TreeFile currently being edited
Staging AreaContents of documents to be submitted
Local RepositorySaved Commit History

Note: git add not only starts tracking the file, but more importantly, puts the snapshot of the current file content of into the staging area.

Therefore, the same file can have both staged and unstaged modifications.

2. Core concepts

Repository

The Git repository contains information such as submission objects, branch references, and historical records.

git init
git clone <url>

The repository usually contains the .git/ directory.

Tracked / Untracked

  • Tracked: Files already tracked by Git.
  • Untracked: Git Files not yet tracked.
  • Modified: The file content has changed.
  • Staged: The modification has entered the staging area.
git status

.gitignore

Used to ignore files that are not yet tracked.

node_modules/
.env
dist/
__pycache__/

Files that have been tracked will continue to be tracked even if .gitignore is added.

Stop tracing but keep local files:

git rm --cached .env

If sensitive information has been submitted to the Git history, stopping the tracking will not clear the leaked content in the existing history. You will also need to revoke the corresponding key and consider cleaning the history.

Commit

Commit can be understood as a complete snapshot of the project at a certain moment, and saves metadata such as parent Commit, author, time and submission information.

A ── B ── C ── D
               ↑
              main

Each Commit has a unique object ID.

HEAD is usually a symbolic reference to the current branch.

HEAD → main → D

Common expressions:

expressionmeaning
HEADcurrent commit
HEAD^first parent commit
HEAD~2Go forward two times along the first parent commit
HEAD~3Go forward three times along the first parent commit
HEAD^2Second parent commit, common in Merge Commit

HEAD^3 is not the first three commits, but the third parent commit.

Detached HEAD

Switch directly to a Commit:

git switch --detach abc123

At this time, HEAD points directly to Commit, not a branch.

Good for checking historical code. If you are ready to continue development here, you should create a new branch:

git switch -c fix/old-version

3. Local branches and remote tracking branches

Git is a distributed version control system.

GitHub:
main         → C

Local:
main         → B
origin/main  → C
  • main: local branch.
  • origin/main: Locally saved remote tracking branch status.
  • origin: The name of the remote repository, usually automatically created by clone.

If a new commit is generated remotely:

GitHub:
A ── B ── C ── D

Local:
main         → B
origin/main  → C

Run:

git fetch origin

Updated to:

main         → B
origin/main  → D

But local main will not be modified directly.

fetch and pull

git fetch origin

Get remote updates without merging the current working branch directly.

git pull

Fetch first, then Merge, Rebase or only Fast-forward depending on the configuration.

Explicitly specify:

git pull --no-rebase
git pull --rebase
git pull --ff-only

For scenarios where you want to avoid accidental merge commits, use --ff-only.

4. Basic commands

Initialization and configuration

git init

git config --global user.name "Your Name"
git config --global user.email "you@example.com"

git clone <url>

View status

git status

git branch
git branch -a
git remote -v

Staging and submitting

git add src/foo.ts

git add .

git commit -m "feat: add user profile"

git add . Add qualified additions, modifications and deletions in the current directory and subdirectories to the staging area.

It is recommended to check before submitting:

git diff --staged

View differences

# Workspace and staging area
git diff

# staging area and HEAD
git diff --staged

# two Commit
git diff A B

# View a single commit
git show <commit>

View history

git log

git log --oneline

git log --oneline --graph --decorate --all

git log -n 5

git log --author="Author Name"

Among them:

git log --oneline --graph --decorate --all

Suitable for viewing branch and merge relationships.

5. Branch management

Create and switch

git branch feature/login

git switch feature/login

# Create and switch
git switch -c feature/login

Delete

# safe delete
git branch -d feature/login

# force delete
git branch -D feature/login

# Delete remote branch
git push origin --delete feature/login

-d checks that the branch has been merged appropriately; -D skips this safety check.

Rename

git branch -m new-name

Push with Upstream

git push -u origin feature/login

-u establishes the tracking relationship between the local branch and the upstream branch.

After that you can usually:

git push
git pull

But the actual Push target is also affected by the Git configuration.

6. Merge: merge branches

Assumptions:

        C ── D  feature
       /
A ── B ── E     main

On main:

git switch main
git merge feature

Result:

        C ── D ──┐
       /          │
A ── B ── E ───── M
                 ↑
                main

Merge Commit M has two parent commits.

Git performs a three-way merger based on common ancestors and changes on both sides.

Fast-forward Merge

If main produces no new commits:

A ── B         main
      \
       C ── D  feature

Execution:

git switch main
git merge feature

Result:

A ── B ── C ── D
                 ↑
             main, feature

At this time, Git only needs to move the branch pointer forward, and does not necessarily create a new Merge Commit.

7. Rebase: Rebase

Assumptions:

A ── B ── C        main
      \
       D ── E      feature

Execute on the feature branch:

git switch feature
git rebase main

Result:

A ── B ── C        main
             \
              D' ── E'  feature

Rebase After reapplying the commits in the branch to the new base commit.

A new Commit ID is usually generated due to changes in information such as the parent commit.

Merge and Rebase

ContrastMergeRebase
original historyReserveRewrite a replayed commit
Submit diagramMay produce forks and Merge Commitusually more linear
shared branchrelatively safeshould not be rewritten arbitrarily
Common usesMerge feature branchesUpdate personal development branch

Common principles:

  • History that has been shared by the team should be given priority to avoid Rebase rewriting.
  • For function branches that are maintained independently, you can use Rebase to organize the history.
  • The details are subject to the team’s Git workflow specification.

8. Merge / Rebase conflict

Conflict example:

<<<<<<< HEAD
const timeout = 30;
=======
const timeout = 60;
>>>>>>> feature

The final content needs to be manually determined and conflict markers removed.

Merge conflict

git status

# Modify conflict files
git add config.ts

git merge --continue

You can also execute git commit to complete the merge under appropriate circumstances.

Give up Merge:

git merge --abort

Rebase conflict

git status

# Modify conflict files
git add config.ts

git rebase --continue

Give up Rebase:

git rebase --abort

Note: When Rebase, the meanings of ours and theirs are easily confused with ordinary Merge, and cannot be mechanically understood as "my code" and "other people's code".

9. Restore、Reset、Revert

All three orders relate to revocation but have different responsibilities.

git restore

Mainly restore the file contents in the work area or staging area.

# Discard unstaged modifications to the file and revert to Index
git restore src/foo.ts

# Cancel the temporary save and keep the workspace modifications
git restore --staged src/foo.ts

# Both the staging area and the workspace are restored to HEAD
git restore --source=HEAD --staged --worktree src/foo.ts

Note: By default git restore file uses Index as the source, which is not necessarily equal to HEAD.

git reset

You can move the Commit pointer of the current branch and decide whether to modify the staging area and work area according to the mode.

modeMove HEADReset IndexReset Working Tree
--softYesNoNo
--mixed (default)YesYesNo
--hardYesYesYes

For example:

# Undo the last Commit,keep staging
git reset --soft HEAD~1

# Undo the last Commit,Keep workspace modifications but unstage them
git reset HEAD~1

# Return to the specified commit and reset the workspace and staging area
git reset --hard abc123

--hard is destructive and may cause uncommitted work to be lost. For commits that have been pulled by others, you generally should not force push them after Reset.

When specifying a file:

git reset HEAD -- src/foo.ts

Just restore the temporary contents of the file to HEAD without moving the current branch.

git revert

Create a new reverse commit without deleting the original history.

A ── B ── C ── D
               ↓ revert C
A ── B ── C ── D ── E
git revert <commit>

Suitable for commits that have been Push to the team's shared branch.

How to choose?

demandRecommended
Discard unstaged modificationsgit restore
Unstagegit restore --staged
Undo the unpushed Commit and retain the modificationsgit reset --soft
Undo Commit on shared branchgit revert
Completely discard local modifications and roll backgit reset --hard, cautious

10. Last modification Commit

Modify submission information:

git commit --amend

Forgot to add file:

git add forgotten.py
git commit --amend --no-edit

--amend actually creates a new Commit replacing the old Commit at the end of the current branch.

Use caution if old commits have been Push into the shared branch.

11. Stash: Temporarily save changes

git stash is used to temporarily save uncommitted work.

git stash

The default is to save staged and unstaged modifications of tracked files, but not ordinary Untracked files.

New files need to be included:

git stash push -u -m "WIP: profile form"

Commonly used commands:

git stash list

# Restore the latest Stash,and remove from the list
git stash pop

# restore but retain Stash
git stash apply

# delete specified Stash
git stash drop stash@{0}

Suitable for temporary switching tasks during development.

Note: stash pop may conflict and the recovery process may not be successful.

12. Cherry-pick: Select the specified submission

Assumptions:

main:     A ── B ── C

feature:  A ── B ── D ── E

Just want to apply the modifications of D to main:

git switch main
git cherry-pick <D>

Result:

main: A ── B ── C ── D'

Applicable scenarios:

  • Pick Bug Fix from other branches.
  • Backport specific fixes to release branches.
  • Don't want to merge the entire feature branch.

Cherry-pick usually creates a new Commit.

13. Reflog: Retrieve lost commits

git reflog records some historical changes of local HEAD and references.

git reflog

For example, executed:

git reset --hard HEAD~2

If you find that the rollback is wrong, you can first pass:

git reflog

Find the original Commit ID.

Then create the recovery branch:

git branch recovery <commit-id>

Or try Reset again after confirming safety.

Need to pay attention to:

  • Reflog is mainly a local record.
  • Reflog entries will expire.
  • There is no guarantee that all uncommitted changes can be retrieved.

It is especially suitable for recovering Reset, Rebase not found after accidental Commit.

14. Tag: version label

Tag is typically used to mark release versions.

Lightweight tags:

git tag v1.0.0

Note tags:

git tag -a v1.0.0 -m "Release v1.0.0"

Push:

git push origin v1.0.0

Check out:

git tag
git show v1.0.0

Tag is different from Branch:

  • Branch usually moves with the new Commit.
  • Tag usually points to a specific object.

15. Force push

git push --force

Remote branch history can be forcibly overwritten, which carries a higher risk.

It is more recommended to use when you really need to rewrite your own branch history:

git push --force-with-lease

It checks that remote references still match local expectations, reducing the risk of overwriting someone else's new commit.

But it does not mean absolute safety, especially in background Fetch or complex team collaboration scenarios, you still need to be cautious.

Do not force push the shared main branch at will.

16. Daily development workflow

Step 1: Create a feature branch

git switch main
git pull --ff-only

git switch -c feature/avatar-upload

Step Two: Develop and Submit

git status
git diff

git add .
git diff --staged

git commit -m "feat: add avatar upload"

Step 3: Push

git push -u origin feature/avatar-upload

Create Pull Request at GitHub, waiting for Review.

Step 4: Modify according to Review

git add .
git commit -m "fix: validate avatar file type"
git push

Step 5: Clean up after PR merge

git switch main
git pull --ff-only

git branch -d feature/avatar-upload

If the remote function branch is not automatically deleted by the platform, it can be deleted on demand:

git push origin --delete feature/avatar-upload