git示例1

参考: Git 原理入门 - 阮一峰的网络日志 (ruanyifeng.com)

示例一:创建仓库

初始化仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 进入目标目录
PS ~> cd .\aliceWorkspace\
# 初始化当前目录为新git仓库
PS ~\aliceWorkspace> git init
Initialized empty Git repository in E:/个人文件归档/笔记-博客文档/软件学习/git/demoforgit/aliceWorkspace/.git/
# 检查仓库目录
PS ~\aliceWorkspace> tree .\.git\
├─hooks
├─info
├─objects
│ ├─info
│ └─pack
└─refs
├─heads
└─tags
# 检查git仓库状态
PS ~\aliceWorkspace> git status
On branch master
No commits yet
nothing to commit (create/copy files and use "git add" to track)

配置仓库参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 原始./.git/config内容
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true

# 设置目标远程仓库地址
PS ~\aliceWorkspace> git remote add origin
git@github.com:WilsonGoGo/gitLearning.git
# 对应./.git/config中内容
[remote "origin"]
url = git@github.com:WilsonGoGo/gitLearning.git
fetch = +refs/heads/*:refs/remotes/origin/*

# 设置当前仓库用户名与邮箱
PS ~\aliceWorkspace> git config user.name "WilsonGoGo"
PS ~\aliceWorkspace> git config user.email
"wilson6174wujunqi@outlook.com"
# 对应./.git/config中内容
[user]
name = WilsonGoGo
email = wilson6174wujunqi@outlook.com

示例二:简单提交

修改工作区

1
2
3
### 指令部分 ###
# 创建文件
PS ~\aliceWorkspace> echo "repo inited" > README.md
1
2
3
4
5
6
7
8
9
10
11
12
### 原理部分 ###
# 检查git仓库状态,可以看到提示新文件README.md未被追踪
PS ~\aliceWorkspace> git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
# 检查git仓库的git对象,也没有README.md对应的git对象
~\aliceWorkspace> tree .\.git\objects\
├─info
└─pack

提交暂存区

1
2
3
### 指令部分 ###
# 提交刚刚的文件至暂存区
PS ~\aliceWorkspace> git add .\README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
### 原理部分 ###
# 检查git仓库状态
PS ~\aliceWorkspace> git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
# 检查git对象
PS ~\aliceWorkspace> tree .\.git\objects\
├─01/ccc646d113420d128301639686e16799ece787
├─info
└─pack
PS ~\aliceWorkspace> git cat-file -t 01cc
blob # 该对象是blob类型,说明其实某文件的备份
PS ~\aliceWorkspace> git cat-file -p 01cc
ÿþrepo inited # 该blob对象储存的内容就是之前写入README.md的内容

移除暂存区

1
2
3
4
5
6
7
8
9
### 指令部分 ###
# 想把刚刚加入暂存区的README.md移除
PS ~\aliceWorkspace> git rm .\README.md
error: the following file has changes staged in the index:
README.md
(use --cached to keep the file, or -f to force removal)
# 由于刚刚已经提交
PS ~\aliceWorkspace> git rm --cached .\README.md
rm 'README.md'
1
2
3
4
5
6
7
8
9
10
11
12
13
### 原理部分 ###
# 检查git对象,发现之前README.md对应的blob对象仍然存在
PS ~\aliceWorkspace> tree .\.git\objects\
├─01/ccc646d113420d128301639686e16799ece787 # blob,内容是首次add的README.md
├─info
└─pack
# 检查状态,该文件又恢复至untracked状态
PS ~\aliceWorkspace> git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md

再次修改

1
2
3
4
5
### 指令部分 ###
# 重新修改文件内容
PS ~\aliceWorkspace> echo "repo inited --wilson" > .\README.md
# 再次提交
PS ~\aliceWorkspace> git add .\README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
### 原理部分 ###
# 检查git仓库状态
PS ~\aliceWorkspace> git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
# 检查git对象,发现多了一个blob类型记录了新的README.md文件内容
PS ~\aliceWorkspace> tree .\.git\objects\
├─01/ccc646d113420d128301639686e16799ece787 # blob,内容是首次add的README.md
├─74/70c63fd32dc148b1c9cf317c5fbd2a9616b492
├─info
└─pack
PS ~\aliceWorkspace> git cat-file -p 7470
ÿþrepo inited --wilson
# 再次执行git gc进行垃圾回收打包,发现git对象中刚刚的新blob类型消失了
PS ~\aliceWorkspace> git gc
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), done.
Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
PS ~\aliceWorkspace> tree .\.git\objects\
├─01/ccc646d113420d128301639686e16799ece787
├─info
└─pack

使用commit进行提交

1
2
3
4
5
6
### 指令部分 ###
# 进行提交,即生成了一个项目的快照
PS ~\aliceWorkspace> git commit -m "first commit : init README.md"
[master (root-commit) becd906] first commit : init README.md
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
### 原理部分 ###
PS ~\aliceWorkspace> git status
On branch master
nothing to commit, working tree clean
# 检查git对象
PS ~\aliceWorkspace> tree .\.git\objects\
├─01/ccc646d113420d128301639686e16799ece787 # blob,内容是首次add的README.md
├─9d/7e540963b86926d49c605df45e40ee64c3aca5
├─be/cd90604bc3786383cc3dec2b58befc221743ef
├─info
└─pack
# tree类型相当于一个路径,他会指向该路径下的所有文件对应的blob对象以及子目录对应的tree对象
# 这里这个tree相当于整个项目快照的根路径,它指向之前修改后的README.md文件对应的7470的blob对象
PS ~\aliceWorkspace> git cat-file -t 9d7e
tree
PS ~\aliceWorkspace> git cat-file -p 9d7e
100644 blob 7470c63fd32dc148b1c9cf317c5fbd2a9616b492 README.md
# 每个commit类型其实就是一个项目的快照
# 其中commit类型对象一定指向一个tree类型,这个tree相当于当前快照的目录结构树的根节点,可以理解为项目的根路径对应的tree类型,通过这个tree类型遍历得到快照内所有的文件对应的blob对象
# 其中author和committer记录的提交这次commit操作的用户和时间
# 其中“first commit : init README.md”是操作commit时-m内包含的提交注释信息,是每次commit操作必须携带的
PS ~\aliceWorkspace> git cat-file -t becd
commit
PS ~\aliceWorkspace> git cat-file -p becd
tree 9d7e540963b86926d49c605df45e40ee64c3aca5
author WilsonGoGo <wilson6174wujunqi@outlook.com> 1663302147 +0800
committer WilsonGoGo <wilson6174wujunqi@outlook.com> 1663302147 +0800
first commit : init README.md

示例三:分支管理

一般情况下,开发一个项目时,我们需要保证主分支上的版本都是可用的,然后基于可用的主分支去新建一个dev分支用于测试开发版本

1
2
3
4
5
6
7
8
9
10
11
12
13
# 新建dev分支
PS ~\aliceWorkspace> git branch dev
# 检查所有分支,当前指针仍然处于master分支上
PS ~\aliceWorkspace> git branch
dev
* master
# 切换分支
PS ~\aliceWorkspace> git switch dev
Switched to branch 'dev'
# 检查分支,已经切换成功
PS ~\aliceWorkspace> git branch
* dev
master

进行开发,这里模拟创建task.doc文件记录开发要求(即记录各开发员信息)

1
2
PS ~\aliceWorkspace> new-item task.doc
PS ~\aliceWorkspace> echo "record everyone's name" > .\task.doc

开发结束,进行commit来更新dev分支指向的快照

1
2
3
4
5
6
7
8
### 代码部分 ###
# 提交所有改动至暂存区
PS ~\aliceWorkspace> git add .
# 提交commit保存快照至dev分支
PS ~\aliceWorkspace> git commit -m "dev: init task.doc"
[dev f712190] dev: init task.doc
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 task.doc

通过可视化界面(来自VsCode的gitLens插件),检查分支图:

1663306845322

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
### 原理部分 ###
## 检查git对象 ##
PS ~\aliceWorkspace> tree .\.git\objects\
├─01/ccc646d113420d128301639686e16799ece787 # blob,内容是首次add的README.md
├─78/c2277b22f2c1e22a4d29fbe4cc443dd6f267ad
├─8a/ca54ef6e8b187c21516723fe4e2c16f4104e1b
├─9d/7e540963b86926d49c605df45e40ee64c3aca5 # tree, 首次commit的快照根节点
├─be/cd90604bc3786383cc3dec2b58befc221743ef # commit, master分支的首次commit
├─f7/12190f68a943af3cdf3a911327a51d188f7d9a
├─info
└─pack
# 78c2... blob类型 储存新建的task.doc文件
PS ~\aliceWorkspace> git cat-file -t 78c2
blob
PS ~\aliceWorkspace> git cat-file -p 78c2
ÿþrecord everyone's name
# 8aca... tree类型 是包含task.doc的快照根目录
PS ~\aliceWorkspace> git cat-file -t 8aca
tree
PS ~\aliceWorkspace> git cat-file -p 8aca
100644 blob 7470c63fd32dc148b1c9cf317c5fbd2a9616b492 README.md
100644 blob 78c2277b22f2c1e22a4d29fbe4cc443dd6f267ad task.doc
# f712... commit类型 对应dev分支上刚刚的commit操作 指向8aca...tree类型
PS ~\aliceWorkspace> git cat-file -t f712
commit
PS ~\aliceWorkspace> git cat-file -p f712
tree 8aca54ef6e8b187c21516723fe4e2c16f4104e1b
parent becd90604bc3786383cc3dec2b58befc221743ef
author WilsonGoGo <wilson6174wujunqi@outlook.com> 1663304672 +0800
committer WilsonGoGo <wilson6174wujunqi@outlook.com> 1663304672 +0800
dev: init task.doc

## 检查指针 ##

# 检查HEAD指针 #
# HEAD指针当前值:HEAD指针目前指向dev分支,与dev分支指针同步
PS ~\aliceWorkspace> cat .\.git\HEAD
ref: refs/heads/dev
# HEAD指针历史记录
PS ~\aliceWorkspace> cat .\.git\logs\HEAD
0000000000000000000000000000000000000000 becd90604bc3786383cc3dec2b58befc221743ef WilsonGoGo <wilson6174wujunqi@outlook.com> 1663302147 +0800 commit (initial): first commit : init README.md # 这条记录表示HEAD指针从git初始化时的00...变动至第一次commit(提交了README.md)的becd...快照
becd90604bc3786383cc3dec2b58befc221743ef becd90604bc3786383cc3dec2b58befc221743ef WilsonGoGo <wilson6174wujunqi@outlook.com> 1663303934 +0800 checkout: moving from master to dev # 这条记录表示HEAD指针从master分支移动到dev分支,但是这两个分支目前指向的同一个commit对象becd...,即指向同一个项目快照
becd90604bc3786383cc3dec2b58befc221743ef f712190f68a943af3cdf3a911327a51d188f7d9a WilsonGoGo <wilson6174wujunqi@outlook.com> 1663304672 +0800 commit: dev: init task.doc # 这条记录表示HEAD指针从第一次commit的快照becd...指向了第二次commit(提交了task.doc)的快照f714...

# 检查各分支指针 #
# master分支
# master指针值仍指向刚提交完README.md时提交的commit类型
PS ~\aliceWorkspace> cat .\.git\refs\heads\master
becd90604bc3786383cc3dec2b58befc221743ef
# master指针历史记录
PS ~\aliceWorkspace> cat .\.git\logs\refs\heads\master
0000000000000000000000000000000000000000 becd90604bc3786383cc3dec2b58befc221743ef WilsonGoGo <wilson6174wujunqi@outlook.com> 1663302147 +0800 commit (initial): first commit : init README.md # 该条表示master指针从初始化0000...指向了becd...(首次commit,即README.md的提交)
# dev分支
# dev指针值已经指向刚刚提交了task.doc后的commit类型
PS ~\aliceWorkspace> cat .\.git\refs\heads\dev
f712190f68a943af3cdf3a911327a51d188f7d9a
# dev指针历史记录
PS ~\aliceWorkspace> cat .\.git\logs\refs\heads\dev
0000000000000000000000000000000000000000 becd90604bc3786383cc3dec2b58befc221743ef WilsonGoGo <wilson6174wujunqi@outlook.com> 1663303857 +0800 branch: Created from master # 这条记录表示dev分支从master分支上创建而来
becd90604bc3786383cc3dec2b58befc221743ef f712190f68a943af3cdf3a911327a51d188f7d9a WilsonGoGo <wilson6174wujunqi@outlook.com> 1663304672 +0800 commit: dev: init task.doc # 这条记录表示dev指针从becd...(首次commit,即README.md的提交)指向了f712...(第二次commit,即task.doc的提交)

由于此时,master分支与main分支指向的快照上有所不同,尝试切换分支观察工作区对应文件的变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# master分支
PS ~\aliceWorkspace> git switch master
Switched to branch 'main'
PS ~\aliceWorkspace> ls
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2022/9/16 12:13 46 README.md

# dev分支
PS ~\aliceWorkspace> git switch dev
Switched to branch 'dev'
PS ~\aliceWorkspace> ls
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2022/9/16 12:13 46 README.md
-a---- 2022/9/16 14:43 50 task.doc

可以看出,当分支切换时,工作区对应的文件也会被更改至快照状态

示例三:简单提交

完成前两个示例后,alice希望将仓库同步到远程仓库,这样其他开发员就可以一起对项目进行开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 切换回master主分支,并将其同步至远程
PS ~\aliceWorkspace> git switch master
# github上默认的主分支名称叫mian,我们先把本地master分支推送至远程仓库的main分支上
PS ~\aliceWorkspace> git push origin master:main # 这里的origin值代表目标远程仓库名,这个值在示例一中已经配置过了
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 275 bytes | 275.00 KiB/s, done.
Total 3 (delta 0), reused 1 (delta 0), pack-reused 0
To github.com:WilsonGoGo/gitLearning.git
* [new branch] master -> main
# 还需要将dev分支也一并推送
PS ~\aliceWorkspace> git push --all origin # 这里偷懒使用--all将本地所有分支上传
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 333 bytes | 333.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:WilsonGoGo/gitLearning.git
* [new branch] dev -> dev
* [new branch] master -> master # 这次的--all指令导致master分支被再次推送至远程仓库,并新建同名分支master来储存
# 注:
# 由于github的默认主分支是main,我们第一次push时已经上传过了,而上一次push --all导致远程仓库的master和main分支重复。为了以后操作方便,将本地的master重命名为main,并将github上重复的master分支删除
# 重命名分支
PS ~\aliceWorkspace> git branch -m master main
PS ~\aliceWorkspace> git branch
dev
* main
# 删除远程仓库的master分支
PS ~\aliceWorkspace> git push origin :master
To github.com:WilsonGoGo/gitLearning.git
- [deleted] master

注:这里出现一个问题,就是本地git init的默认分支是master,github建立仓库的默认分支现在已经改为main,在上述操作中因为默认分支名不同,导致了github上有master和main的两个重复分支,以下给出几种方案来避免这个问题:

  1. 在本地初始化仓库时,使用git config --global init.defaultBranch main将本地git仓库默认分支命名为main
  2. 在github创建仓库页面,通过setting选项修改仓库默认分支为master

示例四:拉取仓库

现在程序员bob加入项目的开发,他需要把仓库clone至本地来加入开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 拉取仓库
PS ~\bobWorkspace> git clone git@github.com:WilsonGoGo/gitLearning.git
Cloning into 'gitLearning'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.
# 检查发现只有main分支
PS ~\bobWorkspace\gitLearning> git branch
* main
# 原因是默认隐藏远程分支,用-a查看所有分支
PS ~\bobWorkspace\gitLearning> git branch -a
* main
remotes/origin/HEAD -> origin/main
remotes/origin/dev
remotes/origin/main
# 切换至远程分支dev上
PS ~\bobWorkspace\gitLearning> git checkout -t origin/dev
Switched to a new branch 'dev'
branch 'dev' set up to track 'origin/dev'.

现在bob程序员可以在本地对dev进行开发了

示例五:差异比较

切回alice视角,继续对dev分支进行开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 先创建几个文件
PS ~\aliceWorkspace> new-item nameList.txt
PS ~\aliceWorkspace> mkdir aliceInfo
PS ~\aliceWorkspace> cd .\aliceInfo\
PS ~\aliceWorkspace\aliceInfo> new-item workList.txt
# 将nameList.txt加入暂存区后,尝试切换分支并检查git仓库状态,发现没有区别
# 说明暂存区的文件是不记录对应分支的,只有commit操作时,生成commit快照的同时再移动各branch的指针与HEAD的指针
PS ~\aliceWorkspace> git add nameList.txt
PS ~\aliceWorkspace> git branch alice
PS ~\aliceWorkspace> git switch alice
PS ~\aliceWorkspace> git status
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: nameList.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
aliceInfo/
PS ~\aliceWorkspace> git switch dev
PS ~\aliceWorkspace> git status
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: nameList.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
aliceInfo/

继续开发

1
2
# 向nameList中写入内容
PS ~\aliceWorkspace> echo "alice" > nameList.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
### git diff 原理 ###
# 执行git diff指令
# 注:
# git diff查看的相当于是工作区修改过的文件和缓存区中的文件进行比较
# 因为nameList.txt之前已经git add过一次了,执行git diff指令,git会将工作区目前的nameList进行哈希算法和缓存去的哈希值比较,然后发现存在差异
# 而其他还未加入暂存区的文件,则不会进行diff比较,因此也就未提示
PS ~\aliceWorkspace> git diff
diff --git a/nameList.txt b/nameList.txt
index e69de29..12381d8 100644
Binary files a/nameList.txt and b/nameList.txt differ
# 更新nameList.txt文件至暂存区
PS ~\aliceWorkspace> git add nameList.txt
#
PS ~\aliceWorkspace> git diff # 此时工作区的文件与暂存区的文件是没有差异的
PS ~\aliceWorkspace> git diff HEAD # 比较HEAD指针指向的快照与当前工作区文件差异
diff --git a/nameList.txt b/nameList.txt
new file mode 100644
index 0000000..12381d8
Binary files /dev/null and b/nameList.txt differ # 说明HEAD指针指向的镜像中没有nameList.txt文件,与当前工作区中不同
# 注:
# 当前HEAD指向ref: refs/heads/alice
# 而此时,由于工作区的nameList.txt经历过git add操作,git仓库区有其对应的blob对象(即被标记为追踪的状态),所以才可以通过git diff比对
# 而其他./aliceInfo/workList.txt未经历过git add操作,git仓库区无对应的blob对象(即被标记为未追踪的状态),所以git diff不会将其进行对比

提交对nameList.txt的更改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 提交commit至本地
PS ~\aliceWorkspace> git commit -m "init: nameList.txt"
[alice 6dffd65] init: nameList.txt
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 nameList.txt
# 推送至远程仓库
PS ~\aliceWorkspace> git push origin
--all
Enumerating objects: 8, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 691 bytes | 691.00 KiB/s, done.
Total 7 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), done.
remote:
remote: Create a pull request for 'alice' on GitHub by visiting:
remote: https://github.com/WilsonGoGo/gitLearning/pull/new/alice
remote:
To github.com:WilsonGoGo/gitLearning.git
* [new branch] alice -> alice