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 object636e44c5
RUN:
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
04406b1
RUN:
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/master
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
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
testing
Change 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
testing
Note HEAD
now points to
testing
.
testing
Edit 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)testing
main
Switch 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)main
Note:
main
Edit 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)main
Will 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_x
Delete 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_x
Create 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_x
feature_x
Edit 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_x
main
RUN:
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_x
hotfix
Create 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)hotfix
hotfix
Add 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)hotfix
main
Switch 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
hotfix
Merge 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
main
hotfix
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
hotfix
A 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
main
Create 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_x
Merge 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.md
RUN:
git add note.md
git commit -m "Merge branch main"
OUTPUT:
[feature_x 2f7f7736] Merge branch main
feature_x