There are 4 types of objects in Git.
blobs in Git
contexttrees in Git
contextOn Github, fork a test repo:
https://github.com/cn330/git_branch.git
Then clone your forked repo, e.g. to a local repo
named aa
git clone https://github.com/xxxxxxxxxx/git_branch.git aa
Note: Commit IDs are abbreviated
RUN:
git log --oneline
OUTPUT:
636e44c5 (HEAD -> main, origin/main) Add .gitattributes
ed7759c4 (tag: v0.1) Add .gitignore
4aebcc12 (tag: v0.0) Initial commit

Use Git's plumbing (low-level)
command:
git cat-file -p to print contents of a Git object636e44c5RUN:
git cat-file -p 636e44c5
OUTPUT:
tree 04406b139f533d4133902c606399c1163753a6f0
parent ed7759c44067dccd820c22a3216d7ec193676ea8
author xxxxxxxxxx <xxxxxxxxxx@cn330> 1662039770 +0700
committer xxxxxxxxxx <xxxxxxxxxx@cn330> 1662039770 +0700
Add .gitattributes
A commit object contains some meta data:
root tree => starting directory of this
snapshot
parent commit => previous commit
author
committer
commit message
tree of A CommitFor the commit 636e44c5:
tree is
04406b1RUN:
git cat-file -p 04406b1
OUTPUT:
100644 blob 176a458f94e0ea5272ce67c36bf30b6be9caf623 .gitattributes
100644 blob 1d74e21965c4f858f5f818a270e64e1bfad7d843 .gitignore
100644 blob e94ad8ec6cc44dd273a82c88402d2fbb721a2129 README.md
040000 tree 3ac016e418089a765e99924c8341102c43cf6fc9 dir_a
040000 tree c238a9a592088fba675b5394fd2f298b68e65508 dir_b
A blob object simply contains contents of a file.
Check content of file README.md
RUN:
git cat-file -p e94ad8e
OUTPUT:
# README
A readme file.
There are 3 kinds of tag:
lightweight tag,
annotated tag
signed tag
Check content of tag v0.1, which is an annotated
tag.
RUN:
git cat-file -p v0.1
OUTPUT:
object ed7759c44067dccd820c22a3216d7ec193676ea8
type commit
tag v0.1
tagger xxxxxxxxxx <xxxxxxxxxx@cn330> 1662059984 +0700
First working version
A branch object is simply a pointer/label to a commit
cat-file -p.git
.git/refs/heads/masterCheck log:
RUN:
git log --oneline --graph
OUTPUT:
* 636e44c5 (HEAD -> main, origin/main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
Create a new branch named testing.
RUN:
git branch testing
The command does not print out anything.
List current local branches.
RUN:
git branch
OUTPUT:
testing
* main
Check log:
RUN:
git log --oneline --graph
OUTPUT:
* 636e44c5 (HEAD -> main, origin/main, testing) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
testingChange to branch testing
RUN:
git checkout testing
OUTPUT:
Switched to branch 'testing'
Since version 2.23, git has new command git switch.
RUN:
git switch testing
List current local branches.
RUN:
git branch
OUTPUT:
main
* testing
Check log.
RUN:
git log --oneline
OUTPUT:
* 636e44c5 (HEAD -> testing, origin/main, main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
testingNote HEAD now points to
testing.
testingEdit README.md, add change and make a commit.
RUN:
echo -e "\nMessage in a bottle" >> README.md
git add README.md
git commit -m "Add a message to README.md"
OUTPUT:
[testing 45b92d47] Add a message to README.md
1 file changed, 2 insertions(+), 1 deletion(-)
testing (2)Check log.
RUN:
git log --oneline --graph
OUTPUT:
* 45b92d47 (HEAD -> testing) Add a message to README.md
* 636e44c5 (origin/main, main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
Note where testing, main and
HEAD are.
testing (Graph)testingmainSwitch back to branch main.
RUN:
git checkout main
OUTPUT:
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
main (2)Check log.
RUN:
git log --oneline --graph
OUTPUT:
* 636e44c5 (HEAD -> main, origin/main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
Note:
git log shows only commit in current
branch.main (3)Check log for all branches.
RUN:
git log --oneline --graph --all
OUTPUT:
* 45b92d47 (testing) Add a message to README.md
* 636e44c5 (HEAD -> main, origin/main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
main (Graph)mainNote:
mainEdit README.md, add change and make a commit.
RUN:
echo -e "Be happy" >> README.md
git add README.md
git commit -m "Add a second message to README.md"
OUTPUT:
[main cc2a2e6f] Add a second message to README.md
1 file changed, 1 insertion(+), 1 deletion(-)
main (2)Check log.
RUN:
git log --oneline --graph
OUTPUT:
* cc2a2e6f (HEAD -> main) Add a second message to README.md
* 636e44c5 (origin/main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
main (3)Check log for all branches.
RUN:
git log --oneline --graph --all
OUTPUT:
* cc2a2e6f (HEAD -> main) Add a second message to README.md
| * 45b92d47 (testing) Add a message to README.md
|/
* 636e44c5 (origin/main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
main (Graph)mainWill create a new branch and then delete it.
Create a new branch named fix_x.
RUN:
git branch fix_x
List current local branches.
RUN:
git branch
OUTPUT:
fix_x
* main
testing
Check log for all branches.
RUN:
git log --oneline --graph --all
OUTPUT:
* cc2a2e6f (HEAD -> main, fix_x) Add a second message to README.md
| * 45b92d47 (testing) Add a message to README.md
|/
* 636e44c5 (origin/main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
fix_xDelete branch fix_x.
RUN:
git branch -d fix_x
OUTPUT:
Deleted branch fix_x (was cc2a2e6f).
List current local branches.
RUN:
git branch
OUTPUT:
* main
testing
From your forked of test repo, e.g.
Clone your forked repo, e.g. to a local repo named
bb
RUN:
git clone https://github.com/xxxxxxxxxx/git_branch.git bb
feature_xCreate a new branch named feature_x.
RUN:
git checkout -b feature_x # or git switch -c feature_x
OUTPUT:
Switched to a new branch 'feature_x'
This is equivalent to:
git branch feature_x
git checkout feature_x # or git switch feature_x
feature_x (Graph)feature_xfeature_xEdit README.md, add change and make a commit.
RUN:
echo -e "\nAdd a new feature x" >> README.md
git add README.md
git commit -m "Add feature x"
OUTPUT:
[feature_x 2a5c6158] Add feature x
1 file changed, 2 insertions(+), 1 deletion(-)
feature_x (2)Check log.
RUN:
git log --oneline --graph --all
OUTPUT:
* 2a5c6158 (HEAD -> feature_x) Add feature x
* 636e44c5 (origin/main, origin/HEAD, main) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
Note where feature_x, main and
HEAD are.
feature_x (Graph)feature_xmainRUN:
git checkout main # or git switch main
OUTPUT:
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
Note:
git will not let you switch branchmain (Graph)main after a commit in
feature_xhotfixCreate and switch to a new branch hotfix.
RUN:
git checkout -b hotfix # or git switch -c hotfix
OUTPUT:
Switched to a new branch 'hotfix'
hotfix (Graph)hotfixhotfixAdd a new file note.md to repo.
RUN:
echo "# Note" > note.md
git add note.md
git commit -m "Add note.md"
OUTPUT:
[hotfix 148e070d] Add note.md
1 file changed, 1 insertion(+)
create mode 100644 note.md
hotfix (Graph)hotfixmainSwitch to branch main.
RUN:
git checkout main # or git switch main
OUTPUT:
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
main (Graph)main after a commit on
hotfixMerge commit from hotfix onto current branch
(main).
RUN:
git merge hotfix
OUTPUT:
Fast-forward
note.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 note.md
Check log.
RUN:
git log --oneline --graph --all
OUTPUT:
* 148e070d (HEAD -> main, hotfix) Add note.md
| * 2a5c6158 (feature_x) Add feature x
|/
* 636e44c5 (origin/main, origin/HEAD) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
Note that there is no new commit created.
git simply updates main to another
commit.
hotfix onto
mainhotfix has been merged into
branch main, if there is no further use on branch
hotfix, it can safely be deleted.RUN:
git branch --delete hotfix
OUTPUT:
* 148e070d (HEAD -> main) Add note.md
| * 2a5c6158 (feature_x) Add feature x
|/
* 636e44c5 (origin/main, origin/HEAD) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
hotfixA 3-way merge creates a new commit with 2 parents.
RUN:
git branch # check currrent branch.
OUTPUT:
feature_x
hotfix
* main
Merge new commits from branch feature_x onto current
branch.
RUN:
git merge feature_x
git will ask for commit message if this is a
non-fast-forward merge.OUTPUT:
Merge made by the 'ort' strategy.
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Check log
RUN:
git log --oneline --graph --all
OUTPUT:
* 6b192ed1 (HEAD -> main) Merge branch 'feature_x'
|\
| * 2a5c6158 (feature_x) Add feature x
* | baa8e6ad Add note.md
|/
* 636e44c5 (origin/main, origin/HEAD) Add .gitattributes
* ed7759c4 (tag: v0.1) Add .gitignore
* 4aebcc12 (tag: v0.0) Initial commit
feature_x - no conflictMake sure current branch is main
RUN:
git switch main
OUTPUT:
Your branch is ahead of 'origin/main' by 3 commits.
(use "git push" to publish your local commits)
Move current branch (main) back by 1 commit
RUN:
git reset --hard HEAD~1 # or git reset --hard HEAD@{1}
--hard will replace all tracked files in working
directory with the ones in the specified commit
(HEAD~1 in this case)OUTPUT:
HEAD is now at 148e070d Add note.md
main back by 1 commitSwitch to branch feature_x.
RUN:
git checkout feature_x # or git switch feature_x
OUTPUT:
Switched to branch 'feature_x'
feature_x after reset in
mainCreate a commit that will conflict with latest commit in
main
RUN:
echo "# Note: from feature x" > note.md" > note.md
git add note.md
git commit -m "Add note.md with with feature x"
OUTPUT:
[feature_x 93880b20] Add note.md with with feature x
1 file changed, 1 insertion(+)
create mode 100644 note.md
feature_xMerge commit from main onto current branch
(feature_x).
RUN:
git merge main
OUTPUT:
Auto-merging note.md
CONFLICT (add/add): Merge conflict in note.md
Automatic merge failed; fix conflicts and then commit the result.
Check status of merge conflict.
RUN:
git status
OUTPUT:
On branch feature_x
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both added: note.md
no changes added to commit (use "git add" and/or "git commit -a")
Open the file that causes the conflict, note.md in this
case.
<<<<<<< HEAD marks the start of
change on current branch======= separates the changes from two branches>>>>>>> main marks the end of
change from the other branch that your are trying to mergeTo resolve conflict:
decide to either
delete the conflict markers
<<<<<<<, =======,
>>>>>>>
then add change and commit as usual
Ddelete conflict markers and decide the final change
note.mdRUN:
git add note.md
git commit -m "Merge branch main"
OUTPUT:
[feature_x 2f7f7736] Merge branch main
feature_x