Git教程

Git介绍

开源的分布式版本控制系统,用于敏捷高效地处理任何大大小小的项目。

Git是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

其与常用的版本控制工具 CVS, Subversion 等不同,它采用了分布式版本库的方式,不必服务器端软件支持。

配置

Git 提供了一个叫做 git config 的命令,用来配置或读取相应的工作环境变量,这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。

在 Windows 系统上,Git 会找寻用户主目录下的 .gitconfig 文件。主目录即 $HOME 变量指定的目录,一般都是 C:\Documents and Settings$USER。此外,Git 还会尝试找寻 /etc/gitconfig 文件,只不过看当初 Git 装在什么目录,就以此作为根目录来定位。

用户信息

配置个人的用户名称和电子邮件地址,这是为了在每次提交代码时记录提交者的信息:

1
2
git config --global user.name "970640814"
git config --global user.email 970640814@qq.com

如果用了 –global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定项目中使用其他名字或者电邮,去掉–global选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。

文本编辑器

设置 Git 默认使用的文本编辑器,一般可能会是 Vi 或者 Vim,如果你有其他偏好,可以重新设置:

1
git config --global core.editor "code --wait"

差异分析工具

在解决合并冲突时使用哪种差异分析工具。比如要改用 vimdiff 的话:

1
git config --global merge.tool vimdiff

Git 可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合并工具的输出信息。

查看配置信息

可以使用git config --list 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ git config --list
diff.astextplain.textconv=astextplain
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
http.sslbackend=openssl
http.sslcainfo=D:/Git/Git/mingw64/etc/ssl/certs/ca-bundle.crt
core.autocrlf=true
core.fscache=true
core.symlinks=false
pull.rebase=false
credential.helper=manager
credential.https://dev.azure.com.usehttppath=true
init.defaultbranch=master
user.name=970640814
user.email=970640814@qq.com

有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig 和 /.gitconfig),不过最终 Git 实际采用的是最后一个。这些配置我们也可以在 **/.gitconfig** 或 /etc/gitconfig 看到:

1
vim ~/.gitconfig 

也可以直接查阅某个环境变量的设定,只要把特定的名字跟在后面即可:

1
2
$ git config user.name
970640814

生成SSH密钥

可以生成 SSH 密钥并添加到你的 Git 托管服务(如 GitHub、GitLab 等)上:

1
ssh-keygen -t rsa -b 4096 -C "970640814@qq.com"

查看版本

1
git --version

Git工作区、暂存区和版本库

  • 工作区(Working Directory):就是你在电脑里能看到的目录。
  • 暂存区(Staging Area):英文叫 stage 或 index。一般存放在 .git 目录下的 index 文件(.git/index)中。
  • 版本库(Repository):工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。

工作区、暂存区和版本库

  • 左侧为工作区,右侧为版本库。在版本库中标记为 “index” 的区域是暂存区(stage/index),标记为 “master” 的是 master 分支所代表的目录树。

  • “HEAD” 实际是指向 master 分支的一个”游标”,图示的命令中出现 HEAD 的地方可用 master 来替换。

  • objects 标识的区域为 Git 的对象库,实际位于 “.git/objects” 目录下,里面包含了创建的各种对象及内容。

  • 当对工作区修改(或新增)的文件执行 git add 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。

  • 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新,即 master 指向的目录树就是提交时暂存区的目录树。

  • 当执行 git reset HEAD 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。

  • 当执行 git rm --cached <file> 命令时,会直接从暂存区删除文件,工作区则不做出改变。

  • 当执行 git checkout . 或者 git checkout -- <file> 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区中的改动。

  • 当执行 git checkout HEAD . 或者 git checkout HEAD <file> 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

工作区

本地计算机上的项目目录,你在这里进行文件的创建、修改和删除操作。工作区包含了当前项目的所有文件和子目录。

特点:

  • 显示项目的当前状态。
  • 文件的修改在工作区中进行,但这些修改还没有被记录到版本控制中。

暂存区

临时存储区域,它包含了即将被提交到版本库中的文件快照,在提交之前,你可以选择性地将工作区中的修改添加到暂存区。

特点:

  • 暂存区保存了将被包括在下一个提交中的更改。
  • 你可以多次使用 git add 命令来将文件添加到暂存区,直到你准备好提交所有更改。

常用命令:

1
2
3
git add filename       # 将单个文件添加到暂存区
git add . # 将工作区中的所有修改添加到暂存区
git status # 查看哪些文件在暂存区中

版本库

包含项目的所有版本历史记录。每次提交都会在版本库中创建一个新的快照,这些快照是不可变的,确保了项目的完整历史记录。

特点:

  • 版本库分为本地版本库和远程版本库,这里主要指本地版本库。
  • 本地版本库存储在 .git 目录中,它包含了所有提交的对象和引用。

常用命令:

1
2
3
4
git commit -m "Commit message"   # 将暂存区的更改提交到本地版本库
git log # 查看提交历史
git diff # 查看工作区和暂存区之间的差异
git diff --cached # 查看暂存区和最后一次提交之间的差异

工作区、暂存区和版本库之间的关系

1、工作区 -> 暂存区

使用 git add 命令将工作区中的修改添加到暂存区。

1
git add filename

2、暂存区 -> 版本库

使用 git commit 命令将暂存区中的修改提交到版本库。

1
git commit -m "Commit message"

3、版本库 -> 远程仓库

使用 git push 命令将本地版本库的提交推送到远程仓库。

1
git push origin branch-name

4、远程仓库 -> 本地版本库

使用 git pull 或 git fetch 命令从远程仓库获取更新。

1
2
3
4
git pull origin branch-name
# 或者
git fetch origin branch-name
git merge origin/branch-name

Git工作流程

克隆仓库

1
git clone https://github.com/970640814/970640814.github.io.git

创建新分支

为了避免直接在 main 或 master 分支上进行开发,通常会创建一个新的分支:

1
git checkout -b new-feature

暂存文件

将修改过的文件添加到暂存区,以便进行下一步的提交操作:

1
2
3
git add filename
# 或者添加所有修改的文件
git add .

提交更改

将暂存区的更改提交到本地仓库,并添加提交信息:

1
git commit -m "Add new feature"

拉取最新更改

在推送本地更改之前,最好从远程仓库拉取最新的更改,以避免冲突:

1
2
3
git pull origin main
# 或者如果在新的分支上工作
git pull origin new-feature

推送更改

将本地的提交推送到远程仓库:

1
git push origin new-feature

删除分支

如果不再需要新功能分支,可以将其删除:

1
git branch -d new-feature

或者从远程仓库删除分支:

1
git push origin --delete new-feature

Git创建仓库

git init

Git 使用 git init 命令来初始化一个 Git 仓库,Git 很多命令都需要在 Git 的仓库中运行,所以 git init 是使用 Git 的第一个命令。执行完成 git init 命令后,Git 仓库会生成一个 .git 目录,该目录包含了资源的所有元数据,其他的项目目录保持不变。

1
2
3
4
5
6
# 创建并进入新目录
mkdir gitLearn
cd gitLearn
# 使用当前目录作为 Git 仓库,只需使它初始化。
git init
git init gitLearn/

初始化后,会在 gitLearn 目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中。

如果当前目录下有几个文件想要纳入版本控制,需要先用 git add 命令告诉 Git 开始对这些文件进行跟踪,然后提交:

1
2
3
4
5
6
7
8
9
10
git add *.py
git add README
# git commit -m '初始化项目版本'
git commit -m '0.1'

[master (root-commit) e4eac22] 0.1
3 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 1.py
create mode 100644 2.py
create mode 100644 README.md

git clone

使用 git clone 从现有 Git 仓库中拷贝项目:

1
2
3
4
5
git clone <repo>
# 克隆到指定的目录
git clone <repo> <directory>
# 例如:
$ git clone git://github.com/schacon/grit.git mygrit

配置

git 的设置使用 git config 命令。

显示当前的 git 配置信息:

1
$ git config --list

编辑 git 配置文件:

1
$ git config -e    # 针对当前仓库 

或者:

1
$ git config -e --global   # 针对系统上所有仓库

设置提交代码时的用户信息:

1
2
$ git config --global user.name "970640814"
$ git config --global user.email 970640814@qq.com

如果去掉 –global 参数只对当前仓库有效。

Git基本操作

创建仓库命令

git 创建仓库命令:

命令 说明
git init 初始化仓库
git clone 拷贝一份远程仓库,也就是下载一个项目。

提交与修改

Git 的工作就是创建和保存你的项目的快照及与之后的快照进行对比。

有关创建与提交项目快照的命令:

命令 说明
git add 添加文件到暂存区
git status 查看仓库当前的状态,显示有变更的文件。
git diff 比较文件的不同,即暂存区和工作区的差异。
git difftool 使用外部差异工具查看和比较文件的更改。
git range-diff 比较两个提交范围之间的差异。
git commit 提交暂存区到本地仓库。
git reset 回退版本。
git rm 将文件从暂存区和工作区中删除。
git mv 移动或重命名工作区文件。
git notes 添加注释。
git checkout 分支切换。
git switch (Git 2.23 版本引入) 更清晰地切换分支。
git restore (Git 2.23 版本引入) 恢复或撤销文件的更改。
git show 显示 Git 对象的详细信息。

提交日志

命令 说明
git log 查看历史提交记录
git blame <file> 以列表形式查看指定文件的历史修改记录
git shortlog 生成简洁的提交日志摘要
git describe 生成一个可读的字符串,该字符串基于 Git 的标签系统来描述当前的提交

远程操作

命令 说明
git remote 远程仓库操作
git fetch 从远程获取代码库
git pull 下载远程代码并合并
git push 上传远程代码并合并
git submodule 管理包含其他 Git 仓库的项目

文件状态的转换流程

未跟踪(Untracked): 新创建文件最初是未跟踪的。它们存在于工作目录中,但没有被 Git 跟踪。

1
2
touch newfile.txt  # 创建一个新文件
git status # 查看状态,显示 newfile.txt 未跟踪

已跟踪(Tracked): 通过 git add 命令将未跟踪的文件添加到暂存区后,文件变为已跟踪状态。

1
2
git add newfile.txt  # 添加文件到暂存区
git status # 查看状态,显示 newfile.txt 在暂存区

已修改(Modified): 对已跟踪的文件进行更改后,这些更改会显示为已修改状态,但这些更改还未添加到暂存区。

1
2
echo "Hello, World!" > newfile.txt  # 修改文件
git status # 查看状态,显示 newfile.txt 已修改

已暂存(Staged): 使用 git add 命令将修改过的文件添加到暂存区后,文件进入已暂存状态,等待提交。

1
2
git add newfile.txt  # 添加文件到暂存区
git status # 查看状态,显示 newfile.txt 已暂存

已提交(Committed): 使用 git commit 命令将暂存区的更改提交到本地仓库后,这些更改被记录下来,文件状态返回为已跟踪状态。

1
2
git commit -m "Added newfile.txt"  # 提交更改
git status # 查看状态,工作目录干净

Git分支管理

Git 分支管理是 Git 强大功能之一,能够让多个开发人员并行工作,开发新功能、修复 bug 或进行实验,而不会影响主代码库。

几乎每一种版本控制系统都以某种形式支持分支,一个分支代表一条独立的开发线。使用分支意味着你可以从开发主线上分离开来,然后在不影响主线的同时继续工作。Git 分支实际上是指向更改快照的指针。

创建分支

创建新分支并切换到该分支:

1
2
3
git checkout -b <branchname>
#例如
git checkout -b feature-xyz

切换分支命令:

1
2
3
git checkout (branchname)
#例如
git checkout main

查看分支

查看所有分支:

1
git branch

查看远程分支:

1
git branch -r

查看所有本地和远程分支:

1
git branch -a

合并分支

将其他分支合并到当前分支:

1
2
3
4
5
git merge <branchname>

#例如,切换到 main 分支并合并 feature-xyz 分支
git checkout main
git merge feature-xyz

解决合并冲突

当合并过程中出现冲突时,Git 会标记冲突文件,你需要手动解决,打开冲突文件,按照标记解决冲突。

删除分支

删除本地分支:

1
git branch -d <branchname>

强制删除未合并的分支:

1
git branch -D <branchname>

删除远程分支:

1
git push origin --delete <branchname>

实例

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
97064@▒▒Ҳ MINGW64 /d/Git/projects
$ mkdir gitdemo

97064@▒▒Ҳ MINGW64 /d/Git/projects
$ git init
Initialized empty Git repository in D:/Git/projects/.git/

97064@▒▒Ҳ MINGW64 /d/Git/projects (master)
$ touch README

97064@▒▒Ҳ MINGW64 /d/Git/projects (master)
$ git add README

97064@▒▒Ҳ MINGW64 /d/Git/projects (master)
$ git commit -m '第一次版本提交'
[master (root-commit) 2e8f8d0] 第一次版本提交
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README

# 手动创建分支
$ git branch testing

# 列出分支
$ git branch
* master
testing

$ ls
README
$ echo 'MaYe' > test.txt
$ git add .
$ git commit -m 'add test.txt'
[master 3e92c19] add test.txt
1 file changed, 1 insertion(+)
create mode 100644 test.txt
$ ls
README test.txt
# 切换分支
$ git checkout testing
Switched to branch 'testing'
$ ls
README
#切换分支
$ git checkout master
Switched to branch 'master'
$ ls
README test.txt

# 创建新分支并立即切换到该分支下
$ git checkout -b newtest
Switched to a new branch 'newtest'

# 在该分支下删除并重新创建文件
$ git rm test.txt
rm 'test.txt‘
$ ls
README
$ touch Maye.php
$ git add .
$ git commit -am 'removed test.txt、add Maye.php'
[newtest c1501a2] removed test.txt、add runoob.php
2 files changed, 1 deletion(-)
create mode 100644 runoob.php
delete mode 100644 test.txt

# 查看不同分支状态
$ ls
README maye.php
$ git checkout master
Switched to branch 'master'
$ ls
README test.txt

# 删除分支
$ git branch -d testing
Deleted branch testing (was 2e8f8d0).

# 合并分支
# 将 newtest 分支合并到主分支去,test.txt 文件被删除
$ git merge newtest
Updating 9d0c700..6c01565
Fast-forward
README => gitdemo/maye.php | 0
gitdemo/test.txt | 1 -
2 files changed, 1 deletion(-)
rename README => gitdemo/maye.php (100%)
delete mode 100644 gitdemo/test.txt
$ ls
README maye.php
$ git branch -d newtest

# 合并冲突
$ git checkout -b change_site
Switched to a new branch 'change_site'
$ vim maye.php
<?php
echo 'maye';
?>
$ git commit -am 'changed the maye.php'
[change_site 7774248] changed the maye.php
1 file changed, 3 insertions(+)

# 将修改的内容提交到change_site分支。 现在,假如切换回 master 分支我们可以看内容恢复到我们修改前的(空文件,没有代码),我们再次修改 maye.php 文件。
$ git checkout master
$ vim maye.php
<?php
echo 1;
?>
$ git diff
warning: in the working copy of 'gitdemo/maye.php', LF will be replaced by CRLF the next time Git touches it
diff --git a/gitdemo/maye.php b/gitdemo/maye.php
index e69de29..04ccc27 100644
--- a/gitdemo/maye.php
+++ b/gitdemo/maye.php
@@ -0,0 +1,4 @@
+<?php
+echo 1;
+?>
+
$ git commit -am '修改代码'
warning: in the working copy of 'gitdemo/maye.php', LF will be replaced by CRLF the next time Git touches it
[master 82232db] 修改代码
1 file changed, 4 insertions(+)

# 合并分支
$ git merge change_site
Auto-merging gitdemo/maye.php
CONFLICT (content): Merge conflict in gitdemo/maye.php
Automatic merge failed; fix conflicts and then commit the result

# 查看并解决冲突内容
$ cat maye.php
<?php
<<<<<<< HEAD
echo 1;
?>

=======
echo 'maye';
?>
>>>>>>> change_site
$ vim maye.php
<?php
echo 1;
=======
echo 'maye';
?>

$ git diff
diff --cc gitdemo/maye.php
index 04ccc27,ac92928..0000000
--- a/gitdemo/maye.php
+++ b/gitdemo/maye.php
@@@ -1,4 -1,3 +1,5 @@@
<?php
+echo 1;
++=======
+ echo 'maye';
?>
-
# 可以用 git add 要告诉 Git 文件冲突已经解决
$ git status -s
UU maye.php
$ git add maye.php
$ git status -s
M runoob.php
$ git commit
[master 88afe0e] Merge branch 'change_site'
# 成功解决了合并中的冲突,并提交了结果。

命令手册

命令 说明 用法示例
git branch 列出、创建或删除分支。它不切换分支,只是用于管理分支的存在。 git branch:列出所有分支 git branch new-branch:创建新分支 git branch -d old-branch:删除分支
git checkout 切换到指定的分支或恢复工作目录中的文件。也可以用来检出特定的提交。 git checkout branch-name:切换分支 git checkout file.txt:恢复文件到工作区 git checkout <commit-hash>:检出特定提交
git switch 专门用于切换分支,相比 git checkout 更加简洁和直观,主要用于分支操作。 git switch branch-name:切换到指定分支 git switch -c new-branch:创建并切换到新分支
git merge 合并指定分支的更改到当前分支。 git merge branch-name:将指定分支的更改合并到当前分支
git mergetool 启动合并工具,以解决合并冲突。 git mergetool:使用默认合并工具解决冲突 git mergetool --tool=<tool-name>:指定合并工具
git log 显示提交历史记录。 git log:显示提交历史 git log --oneline:以简洁模式显示提交历史
git stash 保存当前工作目录中的未提交更改,并将其恢复到干净的工作区。 git stash:保存当前更改 git stash pop:恢复最近保存的更改 git stash list:列出所有保存的更改
git tag 创建、列出或删除标签。标签用于标记特定的提交。 git tag:列出所有标签 git tag v1.0:创建一个新标签 git tag -d v1.0:删除标签
git worktree 允许在一个仓库中检查多个工作区,适用于同时处理多个分支。 git worktree add <path> branch-name:在指定路径添加新的工作区并切换到指定分支 git worktree remove <path>:删除工作区

Git查看提交历史

Git 提供了多种命令和选项来查看提交历史,从简单的日志到详细的差异对比。一般常用两个命令:

  • git log - 查看历史提交记录。
  • git blame <file> - 以列表形式查看指定文件的历史修改记录。

git log

在使用 Git 提交若干更新后,又或者克隆了某个项目,想回顾下提交历史,可以使用 git log 命令查看。

git log 命令用于查看 Git 仓库中提交历史记录。显示了从最新提交到最早提交的所有提交信息,包括提交的哈希值、作者、提交日期和提交消息等。基本语法:git log [选项] [分支名/提交哈希]

常用的选项包括:

  • -p:显示提交的补丁(具体更改内容)。
  • --oneline:以简洁的一行格式显示提交信息。
  • --graph:以图形化方式显示分支和合并历史。
  • --decorate:显示分支和标签指向的提交。
  • --author=<作者>:只显示特定作者的提交。
  • --since=<时间>:只显示指定时间之后的提交。
  • --until=<时间>:只显示指定时间之前的提交。
  • --grep=<模式>:只显示包含指定模式的提交消息。
  • --no-merges:不显示合并提交。
  • --stat:显示简略统计信息,包括修改的文件和行数。
  • --abbrev-commit:使用短提交哈希值。
  • --pretty=<格式>:使用自定义的提交信息显示格式。

示例:

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
61
62
63
64
65
66
67
68
69
70
71
72
73
$ git log
commit 5aa037d053bc9a95eb4f3cbfa4e7aed47782caae (HEAD -> master)
Merge: 82232db 089d89b
Author: 970640814 <970640814@qq.com>
Date: Tue Oct 29 22:01:36 2024 +0800

Merge branch 'change_site'

commit 82232db5311723912d0cb683ccfe0afaaae3cab6
Author: 970640814 <970640814@qq.com>
Date: Tue Oct 29 21:56:29 2024 +0800

修改代码

commit 089d89b48aaede46980d99c6b04aa8a579ddad7f (change_site)
Author: 970640814 <970640814@qq.com>
Date: Tue Oct 29 21:52:13 2024 +0800

changed the maye.php

commit 6c01565734aa02047ce9b73c97b9274f18d09c8b
Author: 970640814 <970640814@qq.com>
Date: Tue Oct 29 21:39:44 2024 +0800

# 用 --oneline 选项来查看历史记录的简洁的版本,查看此项目的开发历史
$ git log --oneline
5aa037d (HEAD -> master) Merge branch 'change_site'
82232db 修改代码
089d89b (change_site) changed the maye.php
6c01565 removed test.txt、add maye.php
9d0c700 add test.txt
2e8f8d0 第一次版本提交

# 用 --graph 选项,查看历史中什么时候出现了分支、合并,可以更清楚明了地看到何时工作分叉、又何时归并
$ git log --oneline --graph
* 5aa037d (HEAD -> master) Merge branch 'change_site'
|\
| * 089d89b (change_site) changed the maye.php
* | 82232db 修改代码
|/
* 6c01565 removed test.txt、add maye.php
* 9d0c700 add test.txt
* 2e8f8d0 第一次版本提交

# 用 --reverse 参数来逆向显示所有日志
$ git log --reverse --oneline
2e8f8d0 第一次版本提交
9d0c700 add test.txt
6c01565 removed test.txt、add maye.php
089d89b (change_site) changed the maye.php
82232db 修改代码
5aa037d (HEAD -> master) Merge branch 'change_site'

# 如果只想查找指定用户的提交日志可以使用命令:git log --author,如果要指定日期,可以执行几个选项:--since 和 --before,但是你也可以用 --until 和 --after
$ git log --author=970640814 --oneline -5
5aa037d (HEAD -> master) Merge branch 'change_site'
82232db 修改代码
089d89b (change_site) changed the maye.php
6c01565 removed test.txt、add maye.php
9d0c700 add test.txt
$ git log --oneline --before={3.weeks.ago} --after={2010-04-18} --no-merges

# 限制显示提交数
git log -n <number>

# 显示自指定日期之后的提交:
git log --since="2024-01-01"

# 显示指定日期之前的提交:
git log --until="2024-07-01"

# 只显示某个作者的提交:
git log --author="Author Name"

git blame

git blame 命令用于逐行显示指定文件的每一行代码是由谁在什么时候引入或修改的。可以追踪文件中每一行的变更历史,包括作者、提交哈希、提交日期和提交消息等信息。格式如下:git blame [选项] <文件路径>

常用的选项包括:

  • -L <起始行号>,<结束行号>:只显示指定行号范围内的代码注释。
  • -C:对于重命名或拷贝的代码行,也进行代码行溯源。
  • -M:对于移动的代码行,也进行代码行溯源。
  • -C -C-M -M:对于较多改动的代码行,进行更进一步的溯源。
  • --show-stats:显示包含每个作者的行数统计信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 显示文件每一行的代码注释和相关信息:
git blame <文件路径>

# 只显示指定行号范围内的代码注释:
git blame -L <起始行号>,<结束行号> <文件路径>

# 对于重命名或拷贝的代码行进行溯源:
git blame -C <文件路径>

# 对于移动的代码行进行溯源:
git blame -M <文件路径>

# 显示行数统计信息:
git blame --show-stats <文件路径>

$ git blame maye.php
82232db5 (970640814 2024-10-29 21:56:29 +0800 1) <?php
82232db5 (970640814 2024-10-29 21:56:29 +0800 2) echo 1;
5aa037d0 (970640814 2024-10-29 22:01:36 +0800 3) =======
089d89b4 (970640814 2024-10-29 21:52:13 +0800 4) echo 'maye';
82232db5 (970640814 2024-10-29 21:56:29 +0800 5) ?>

恢复和回退

提供了多种方式来恢复和回退到之前的版本,不同的命令适用于不同的场景和需求,几种常见的方法:

  • git checkout:切换分支或恢复文件到指定提交。
  • git reset:重置当前分支到指定提交(软重置、混合重置、硬重置)。
  • git revert:创建一个新的提交以撤销指定提交,不改变提交历史。
  • git reflog:查看历史操作记录,找回丢失的提交。
1、git checkout:检查出特定版本的文件

用于切换分支或恢复工作目录中的文件到指定的提交。

1
2
3
4
5
6
# 恢复工作目录中的文件到某个提交:
git checkout <commit> -- <filename>
# 将 file.txt 恢复到 abc123 提交时的版本:
git checkout abc123 -- file.txt
# 切换到特定提交:
git checkout <commit>

这种方式切换到特定的提交时,处于分离头指针(detached HEAD)状态。

2、git reset:重置当前分支到特定提交

可以更改当前分支的提交历史,它有三种主要模式:–soft、–mixed 和 –hard。

–soft:只重置 HEAD 到指定的提交,暂存区和工作目录保持不变。

1
git reset --soft <commit>

–mixed(默认):重置 HEAD 到指定的提交,暂存区重置,但工作目录保持不变。

1
git reset --mixed <commit>

–hard:重置 HEAD 到指定的提交,暂存区和工作目录都重置。

1
git reset --hard <commit>

例如,将当前分支重置到 abc123 提交:

1
git reset --hard abc123
3、git revert:撤销某次提交

创建一个新的提交,用来撤销指定的提交,它不会改变提交历史,适用于已经推送到远程仓库的提交。

1
2
3
git revert <commit>
# 例如,撤销 abc123 提交:
git revert abc123
4、git reflog:查看历史操作记录

git reflog 命令记录了所有 HEAD 的移动。即使提交被删除或重置,也可以通过 reflog 找回。利用 reflog 可以找到之前的提交哈希,从而恢复到特定状态。

1
2
git reflog
git reset --hard HEAD@{3}

Git标签

达到一个重要的阶段,并希望永远记住提交的快照,你可以使用 git tag 给它打上标签。Git 标签(Tag)用于给仓库中的特定提交点加上标记,通常用于发布版本(如 v1.0, v2.0)。

-a选项意为”创建一个带注解的标签”,不用 -a 选项也可以执行的,但不会记录这标签是啥时候打的,谁打的,也不会让你添加个标签的注解,我们推荐一直创建带注解的标签。标签语法:git tag <tagname>

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
$ git tag -a v1.0 
# 当你执行 git tag -a 命令时,Git 会打开你的编辑器,让你写一句标签注解,就像你给提交写注解一样
# 当我们执行 git log --decorate 时,我们可以看到我们的标签了
$ git log --decorate --oneline --graph
* 5aa037d (HEAD -> master, tag: v1.0) Merge branch 'change_site'
|\
| * 089d89b (change_site) changed the maye.php
* | 82232db 修改代码
|/
* 6c01565 removed test.txt、add maye.php
* 9d0c700 add test.txt
* 2e8f8d0 第一次版本提交


# 如果我们忘了给某个提交打标签,又将它发布了,我们可以给它追加标签。
$ git tag -a v0.9 2e8f8d0
$ git log --oneline --decorate --graph
* 5aa037d (HEAD -> master, tag: v1.0) Merge branch 'change_site'
|\
| * 089d89b (change_site) changed the maye.php
* | 82232db 修改代码
|/
* 6c01565 removed test.txt、add maye.php
* 9d0c700 add test.txt
* 2e8f8d0 (tag: v0.9) 第一次版本提交

# 查看所有标签:
$ git tag
v0.9
v1.0

推送标签到远程仓库

默认情况下,git push 不会推送标签,你需要显式地推送标签。

1
git push origin <tagname>

推送所有标签:

1
git push origin --tags

删除轻量标签

本地删除:

1
git tag -d <tagname>

远程删除:

1
git push origin --delete <tagname>

附注标签

附注标签存储了创建者的名字、电子邮件、日期,并且可以包含标签信息。附注标签更为正式,适用于需要额外元数据的场景。

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
# 创建附注标签语法:
git tag -a <tagname> -m "message"
git tag -a <tagname> -m "Maye.com标签"
$ git tag -a v1.1 -m "Maye.com标签"
# PGP 签名标签命令:
git tag -s <tagname> -m "Maye.com标签"
# 查看标签信息:
git show <tagname>
$ git show v1.1
tag v1.1
Tagger: 970640814 <970640814@qq.com>
Date: Wed Oct 30 15:16:25 2024 +0800

Maye.com标签

commit 5aa037d053bc9a95eb4f3cbfa4e7aed47782caae (HEAD -> master, tag: v1.1, tag: v1.0)
Merge: 82232db 089d89b
Author: 970640814 <970640814@qq.com>
Date: Tue Oct 29 22:01:36 2024 +0800

Merge branch 'change_site'

diff --cc gitdemo/maye.php
index 04ccc27,ac92928..f0a51b0
--- a/gitdemo/maye.php
+++ b/gitdemo/maye.php
@@@ -1,4 -1,3 +1,5 @@@
<?php
+echo 1;
++=======
+ echo 'maye';

Git进阶操作

交互式暂存(Interactive Staging):逐块选择要暂存的更改,精细控制提交内容。

git add 命令可以选择性地将文件或文件的一部分添加到暂存区,这在处理复杂更改时非常有用。

使用**git add -p**:逐块选择要暂存的更改。执行此命令后,Git 会逐块显示文件的更改,你可以选择是否暂存每个块。常用选项包括:

  • y:暂存当前块
  • n:跳过当前块
  • s:拆分当前块
  • e:手动编辑当前块
  • q:退出暂存

Git Stash:临时保存工作进度

允许你临时保存当前工作目录的更改,以便你可以切换到其他分支或处理其他任务。

1
2
3
4
5
6
7
8
9
10
11
12
# 保存当前工作进度:
git stash
# 查看存储的进度:
git stash list
# 应用最近一次存储的进度:
git stash apply
# 应用并删除最近一次存储的进度:
git stash pop
# 删除特定存储:
git stash drop stash@{n}
# 清空所有存储:
git stash clear

Git Rebase:变基

git rebase 命令用于将一个分支上的更改移到另一个分支之上。它可以帮助保持提交历史的线性,减少合并时的冲突。

变基当前分支到指定分支

1
2
3
git rebase <branchname>
# 例如,将当前分支变基到 main 分支:
git rebase main

交互式变基:

1
git rebase -i <commit>

允许你在变基过程中编辑、删除或合并提交。常用选项包括:

  • pick:保留提交
  • reword:修改提交信息
  • edit:编辑提交
  • squash:将当前提交与前一个提交合并
  • fixup:将当前提交与前一个提交合并,不保留提交信息
  • drop:删除提交

Git Cherry-Pick:拣选提交

允许你选择特定的提交并将其应用到当前分支。它在需要从一个分支移植特定更改到另一个分支时非常有用。

拣选提交

1
2
3
git cherry-pick <commit>
# 例如,将 abc123 提交应用到当前分支:
git cherry-pick abc123

处理拣选冲突:如果拣选过程中出现冲突,解决冲突后使用 git cherry-pick --continue 继续拣选。

Git远程仓库(Github)

![Git远程仓库](Git and Github.png)

添加远程库

要添加一个新的远程仓库,可以指定一个简单的名字,以便将来引用,命令格式如下:

1
git remote add [shortname] [url]

由于本地 Git 仓库和 GitHub 仓库之间的传输是通过SSH加密的,所以需要配置验证信息(之后会要求确认路径和输入密码,这使用默认的一路回车就行):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ ssh-keygen -t rsa -C "970640814@qq.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/tianqixin/.ssh/id_rsa):
Enter passphrase (empty for no passphrase): # 直接回车
Enter same passphrase again: # 直接回车
Your identification has been saved in /Users/tianqixin/.ssh/id_rsa.
Your public key has been saved in /Users/tianqixin/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:MDKVidPTDXIQoJwoqUmI4LBAsg5XByBlrOEzkxrwARI 12345678@qq.com
The key's randomart image is:
+---[RSA 3072]----+
|E*+.+=**oo |
|%Oo+oo=o. . |
|%**.o.o. |
|OO. o o |
|+o+ S |
|. |
| |
| |
| |
+----[SHA256]-----+

成功的话会在 ~/ 下生成 .ssh 文件夹,进去,打开 id_rsa.pub,复制里面的 key

回到 github 上,进入 Account => Settings(账户配置),左边选择 SSH and GPG keys,然后点击 New SSH key 按钮,title 设置标题,可以随便填,粘贴在你电脑上生成的 key。

为了验证是否成功,输入以下命令:

1
2
3
$ ssh -T git@github.com
Hi 970640814! You've successfully authenticated, but GitHub does not provide shell access.
# 以上命令说明我们已成功连上 Github。

之后登录后点击” New repository “:

演示1

之后在在Repository name 填入testDemo(远程仓库名) ,其他保持默认设置,点击”Create repository”按钮,就成功地创建了一个新的Git仓库:

创建仓库

创建仓库2

创建成功后,显示如下信息:

创建成功

以上信息说明可以从这个仓库克隆出新的仓库,也可以把本地仓库的内容推送到GitHub仓库。

根据 GitHub 的提示,在本地的仓库下运行命令:

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
$ mkdir testDemo
$ cd testDemo/
$ echo "马也Git测试" >> README.md
$ ls
README.md

$ git init
Initialized empty Git repository in D:/Git/projects/testDemo/.git/
$ git add README.md
warning: in the working copy of 'README.md', LF will be replaced by CRLF the next time Git touches it
$ git commit -m "添加README.md文件"
[master (root-commit) 2b647fb] 添加README.md文件
1 file changed, 1 insertion(+)
create mode 100644 README.md

# 提交到Github
$ git remote add origin git@github.com:970640814/testDemo.git
$ git push -u origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 242 bytes | 242.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To github.com:970640814/testDemo.git
* [new branch] master -> master
branch 'master' set up to track 'origin/master'.

提交成功

查看当前远程库

1
2
3
4
5
6
7
$ git remote
origin
# 执行时加上 -v 参数,你还可以看到每个别名的实际链接地址。
$ git remote -v
origin git@github.com:970640814/testDemo.git (fetch)
origin git@github.com:970640814/testDemo.git (push)

提交远程仓库

1
2
3
4
# 1、从远程仓库下载新分支与数据,该命令执行完后需要执行 git merge 远程分支到你所在的分支。
git fetch
# 2、从远端仓库提取数据并尝试合并到当前分支,该命令就是在执行 git fetch 之后紧接着执行 git merge 远程分支到你所在的任意分支。
git merge

假设你配置好了一个远程仓库,并且想要提取更新的数据,你可以首先执行 git fetch [alias] 告诉 Git 去获取它有你没有的数据,然后可以执行 git merge [alias]/[branch] 以将服务器上的任何更新(假设有人这时候推送到服务器了)合并到你的当前分支。

接下来我们在 Github 上点击” README.md” 并在线修改它:

修改内容

然后我们在本地更新修改:

1
2
3
4
5
6
7
$ git fetch origin
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 935 bytes | 71.00 KiB/s, done.
From github.com:970640814/testDemo
2b647fb..7fe3b78 master -> origin/master

以上信息”2b647fb..7fe3b78 master -> origin/master” 说明 master 分支已被更新,我们可以使用以下命令将更新同步到本地:

1
2
3
4
5
6
7
8
9
10
$ git merge origin/master
Updating 2b647fb..7fe3b78
Fast-forward
README.md | 1 +
1 file changed, 1 insertion(+)

# 查看 README.md 文件内容:
$ cat README.md
马也Git测试
**第一次修改内容**

推送到远程仓库

推送你的新分支与数据到某个远端仓库命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 将你的 [branch] 分支推送成为 [alias] 远程仓库上的 [branch] 分支
git push [alias] [branch]

$ touch test.txt
$ git add test.txt
$ git commit -m "添加到远程"
[master be68fa5] 添加到远程
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test.txt
# 推送到Github
$ git push origin master
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 12 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 287 bytes | 287.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To github.com:970640814/testDemo.git
7fe3b78..be68fa5 master -> master

删除远程仓库

删除远程仓库你可以使用命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
git remote rm [别名]

# 实例
$ git remote add origin2 git@github.com:970640814/testDemo.git
$ git remote -v
origin git@github.com:970640814/testDemo.git (fetch)
origin git@github.com:970640814/testDemo.git (push)
origin2 git@github.com:970640814/testDemo.git (fetch)
origin2 git@github.com:970640814/testDemo.git (push)

# 删除仓库
$ git remote rm origin2
$ git remote -v
origin git@github.com:970640814/testDemo.git (fetch)
origin git@github.com:970640814/testDemo.git (push)