Git使用操作
Git常见的操作
概念
Git是分布式版本控制系统,最早是在Linux下开发的,目的是为了我们可以管理不同版本的文件。
版本控制系统仅跟踪文本变化,如TXT、网页、代码等,记录具体修改。二进制文件如图片、视频,虽可管理但无法追踪具体变化,仅知文件大小变动。
- 工作区:
- 是你在电脑上进行代码编写或文件操作的目录。
- 暂存区:
- 英文名称为
stage
或index
,存放在.git目录下的index文件中。 - 用于临时存储修改过的文件,以便后续提交到版本库。
- 版本库:
- 位于工作区的隐藏目录.git中,包含所有被Git管理的文件及其历史记录。这个版本库里面的所有文件都可以被 Git 管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
Git工作区与版本库关系概述
图示说明:
- 图中左侧代表工作区,是用户进行代码编写和文件操作的区域。
- 图中右侧代表版本库,是Git存储所有被管理文件及其历史记录的地方。
关键:
- 暂存区:
- 位于版本库中,是Git的一个重要组成部分。
- 用于临时存储工作区中修改或新增的文件,以便后续提交。
- 分支与HEAD:
- 在创建Git版本库时,会自动生成一个唯一的
master
分支。 - 同时,会创建一个指向
master
分支的指针,称为HEAD
。
操作流程
- 新建Git仓库:
- 创建时会自动生成一个master分支和指向它的HEAD指针。
- 添加文件到暂存区:
- 使用
git add [file]
命令将一个或多个文件添加到暂存区。 - 使用
git add [dir]
命令添加指定目录及其子目录到暂存区。 - 使用
git add .
命令添加当前目录下所有文件的改动到暂存区。
- 提交文件到版本库:
使用
git commit -m "message"
命令提交暂存区全部内容到本地仓库。提交时必须附带描述信息,用于记录提交细节。
- 查看提交记录:
使用
git log
命令查看历史提交记录。使用
git log --pretty=oneline
命令简化输出信息。
注意事项
在工作区新建或粘贴文件并不等同于向仓库中添加文件,必须执行
git add
和git commit
命令才能完成添加。可以多次
add
不同的文件,然后一次性commit
以提交所有文件。每次提交都会生成一个唯一的commit id(版本号),用于标识该次提交。
.git目录结构
- 包含多个文件和子目录,如branches、COMMIT_EDITMSG、config、description、HEAD、hooks、index、info、logs等。
- HEAD 就是我们的默认指向 master 分支的指针。
- 可以使用
cat ./HEAD
查看指向 master分支的指针 - cat查看上述操作的路径之后,可以看到最新的
commit id
。
![查看最近commitId](/images/查看最近commit id.png)
- 在Git中,对象库(objects database)是存储所有版本控制数据的核心组件。它位于版本库的”.git/objects”目录下,包含了所有被Git管理的文件的历史记录和元数据。
操作
- 在 Git 中,当你想要回退到某个特定的历史版本时,Git允许使用部分 commit id 来代表目标版本。我们不必输入完整的 40 位(对于 SHA-1 哈希)或 64 位(对于 SHA-256 哈希,尽管在大多数 Git 实现中仍常用 40 位表示)commit id,而是可以只输入它的前几位。Git 会尝试根据你提供的前几位字符来匹配唯一的 commit。
配置用户名
和email
git config [可选--global] user.name
git config [可选--global] user.email
指令 | 描述 |
---|---|
git diff |
显示工作目录或暂存区与特定提交之间的差异。 |
git diff --cached |
显示暂存区与上次提交之间的差异。 |
git diff HEAD |
显示工作目录与上次提交(HEAD)之间的差异。 |
git diff <commit1> <commit2> |
显示两个提交之间的差异。 |
git diff --name-only |
仅显示差异文件的名称,不显示具体差异内容。 |
git diff --stat |
显示每个文件的修改统计信息(如插入和删除的行数)。 |
git status |
显示工作目录的状态,包括已修改、暂存和未跟踪的文件。 |
git status -s |
显示简短格式的工作目录状态。 |
git status --porcelain |
显示更为详细的机器可读格式的状态信息。 |
git log |
显示提交历史记录,包括提交的哈希值、作者、日期和提交信息。 |
git log -p |
显示提交历史记录,并附带每个提交的差异(patch)。 |
git log --stat |
显示提交历史记录,并附带每个提交的统计信息。 |
git log --oneline |
以简洁的一行格式显示提交历史记录。 |
git show |
显示特定提交、标签或分支的详细信息,包括差异、提交信息和作者等。 |
git show <commit> |
显示特定提交的详细信息。 |
git show-branch |
显示分支列表及其提交历史,包括合并和未合并的分支。 |
git whatchanged |
显示提交历史记录,类似于 git log ,但包含更多关于文件更改的信息。 |
git blame |
显示文件的每一行是谁在什么时候修改的,用于追溯代码修改历史。 |
回退
git reset 命令总结
语法格式:
1
git reset [--soft | --mixed | --hard] [HEAD]
选项解释:
--mixed
(默认选项):将暂存区的内容回退到指定提交版本,但工作区文件保持不变。--soft
:工作区和暂存区的内容都不变,只将版本库回退到某个指定版本。--hard
:将暂存区与工作区都回退到指定版本,使用前需慎重,因为会丢失未提交的代码。
HEAD 说明:
commit id
:指定退回的版本。HEAD
:当前版本。HEAD^
或HEAD~1
:上一个版本。HEAD^^
或HEAD~2
:上上一个版本。- 以此类推。
使用示例
- 回退到上一个版本(默认 –mixed 选项):git reset HEAD^ # 或 git reset –mixed HEAD^
这会将暂存区的内容回退到上一个版本,但工作区的文件保持不变。如果你需要再次提交这些更改,可以使用 git add
命令将工作区的更改添加到暂存区。
- 软回退(–soft 选项):
1 |
|
这会将版本库回退到上一个版本,但工作区和暂存区的内容都保持不变。这意味着你可以查看上一个版本的内容,同时保留当前工作区和暂存区的更改。
- 硬回退(–hard 选项):
1 |
|
这会将暂存区和工作区都回退到上一个版本。请确保在使用此命令前没有未提交的代码,否则会丢失这些更改。
- 回退到特定提交版本:
1 |
|
将暂存区和工作区都回退到指定的 commit_id
版本。同样,使用前请确保没有未提交的代码。
git checkout -- [file]
命令用于将工作区中的指定文件[file]
恢复到最近一次add
或commit
时的状态。
如果已经add
但是没有commit
- 使用git reset –mixed
如果已经add
并且commit
git reset --hard HEAD^
删除文件
使用git rm
命令
git rm
是Git提供的用于删除文件的主要命令。它不仅会从文件系统中删除文件,还会将删除操作记录到Git的版本历史中。具
执行删除命令:使用
git rm <file>
命令来删除文件,其中<file>
是我们想要删除的文件名。提交删除操作:使用
git commit -m "Delete <filename>"
命令来提交删除操作,其中<filename>
是被删除的文件名。例如,git commit -m "Delete example.txt"
。推送到远程仓库(如果适用):如果我们希望远程仓库也反映这个删除操作,可以使用
git push <branch-name>
命令将更改推送到远程仓库的指定分支上。例如,git push origin master
(如果master
我们想要推送的分支名)。
删除已跟踪文件但保留在文件系统中
有时,我们可能希望从Git仓库中删除文件的跟踪,但保留文件在本地文件系统中。这时可以使用git rm --cached <filename>
命令。执行该命令后我们需要提交这个删除跟踪的操作,但文件本身仍保留在文件系统中。
手动删除文件
如果我们不想使用git rm
命令,也可以手动删除文件并提交更改。步骤如下:
手动删除文件:使用文件管理器或命令行,手动删除我们想要从Git仓库中删除的文件。
将删除操作添加到暂存区:使用
git add .
(或git add <file>
,如果我们只想添加特定文件)命令将文件删除操作添加到暂存区。
分支管理
操作总结
操作 | 命令 | 描述 |
---|---|---|
查看分支列表 | git branch |
列出当前仓库中的所有本地分支。使用git branch -a 或git branch --all 可以查看包括远程分支在内的所有分支。 |
创建新分支 | git branch <branch_name> |
创建一个新的分支,但不会切换到该分支。<branch_name> 是新分支的名称。 |
切换分支 | git checkout <branch_name> |
切换到指定分支进行工作。Git 2.23版本之后,推荐使用git switch <branch_name> 来切换分支。 |
创建并切换分支 | git checkout -b <branch_name> |
或git switch -c <branch_name> (Git 2.23+)创建新分支并立即切换到该分支。 |
合并分支 | git merge <branch_name> |
将指定分支的更改合并到当前分支。如果自动合并过程中出现冲突,需要手动解决。 |
删除分支 | git branch -d <branch_name> |
(-d 或 –delete:安全地删除) 如果分支有未合并的更改,Git会阻止删除。并且不可以删除当前所在分支。使用git branch -D <branch_name> 强制删除未合并的分支。 |
重命名分支 | git branch -m <old_branch_name> <new_branch_name> |
将本地分支的名称从<old_branch_name> 更改为<new_branch_name> 。 |
推送分支到远程仓库 | git push origin <branch_name> |
将本地分支推送到远程仓库,并创建相应的远程分支(如果远程仓库中不存在该分支)。 |
拉取远程分支到本地 | git checkout -b <local_branch_name> origin/<remote_branch_name> |
创建一个新的本地分支,并将其与远程仓库中的指定分支建立追踪关系。然后切换到该本地分支。 |
设置上游分支 | git branch --set-upstream-to=origin/<branch_name> <local_branch_name> |
显式设置本地分支的上游分支(远程跟踪分支)。这有助于git pull 和git push 等命令知道应该与哪个远程分支进行交互。 |
概念
时间线和分支:
- 在Git中,每次提交都会创建一个新的版本,这些版本像珠子一样被串在一条时间线上。
- 这条时间线在Git中被理解为一个分支。初始时,只有一个分支,即主分支,通常被称为
master
分支(在较新的Git版本中,默认分支名可能已更改为main
)。
HEAD指针:
HEAD
是一个特殊的指针,在Git中用于标识当前所在的分支。- 严格来说,
HEAD
并不直接指向提交,而是指向当前分支的最新提交。由于初始时只有master
分支,所以HEAD
指向master
。 - 当
master
分支随着新的提交而向前移动时,HEAD
也随之移动,始终指向master
分支的最新提交。
分支的移动:
- 每次提交时,
master
分支都会向前移动一步,指向新的提交。 - 随着不断提交,
master
分支的线会越来越长,记录着项目的完整历史。 HEAD
始终紧跟master
分支,因此也始终指向当前分支的最新提交。
- 每次提交时,
合并冲突
什么叫分支冲突?
当两个或多个开发者在同一时间对同一个文件(或同一文件的相同部分)进行了不同的修改,并在尝试合并这些修改时,Git无法自动合并这些更改,从而产生的冲突现象。这种情况通常发生在Git版本控制系统中,特别是在合并或切换分支的过程中。
此时,需要手动解决冲突。Git会在冲突的文件中添加特殊的标记(如<<<<<<<
、=======
、>>>>>>>
)来标识不同分支的修改部分。
如何处理分支冲突?
处理分支冲突通常涉及以下几个步骤:
- 定位冲突文件:
- 使用
git status
命令查看当前分支的状态,冲突的文件会被标记为“unmerged”。
- 查看冲突内容:
- 使用文本编辑器打开冲突的文件,查看冲突的具体内容。Git会在冲突部分周围用特殊符号标记(如
<<<<<<< HEAD
、=======
、>>>>>>> branchname
),其中<<<<<<< HEAD
和=======
之间的内容是当前分支的修改,=======
和>>>>>>> branchname
之间的内容是要合并的分支的修改。
- 手动解决冲突:
- 手动编辑文件,将冲突的部分修改为我们期望的内容。可以保留一个分支的修改,也可以将两个分支的修改合并。同时,需要删除Git添加的冲突标记。
- 添加修改后的文件:
- 使用
git add filename
命令将解决冲突后的文件添加到暂存区。
- 提交解决方案:
- 使用
git commit
命令提交解决方案。
查看合并后的情况
git log --graph --pretty=oneline --abbrev-commit
命令会生成一个包含图形化分支表示、每行显示一个提交以及使用简短哈希值的提交历史记录。
- **
--graph
**:- 这个选项会在输出中包含一个图形化的表示,用来展示提交之间的分支和合并关系。这可以帮助你更直观地理解项目的历史流和分支结构。
- **
--abbrev-commit
**:- 这个选项会使
git log
显示简短的提交哈希值,而不是完整的 40 个字符的哈希值。这可以使输出更加紧凑和易读。
- 这个选项会使
不同合并模式
- Fast-forward 代表“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
- 缺点:查看支历史时,会丢掉分支信息,看不出来最新提交到底是 merge 进来的还是正常提交的。
- 禁用
Fast-forward
,那么就会在 merge 时生成⼀个新的 commit ,这样,从分支历史上就可以看出分支信息。
保存git stash
可以将当前的工作区信息进行储藏,被储藏的内容可以在将来某个时间恢复出来。
git stash list
,恢复现场呢?我们可以使用git stash pop
命令。恢复的同时会把stash也删了。另外,恢复现场也可以采用
git stash apply
恢复,但是恢复后,stash内容并不删除,你需要用git stash drop
来删除;
master
分支版本领先当前分支
- 解决这个问题的一个好的建议就是:在自己的分支上合并下 master ,再让 master 去合并dev 。这样做的目的是有冲突可以在本地分支解决并进行测试,而不影响 master。
添加SSH认证
一、生成SSH密钥对
打开终端或命令行界面:首先,我们需要在本地计算机上打开终端或命令行界面。
生成SSH密钥对:输入命令
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
来生成SSH密钥对。其中,-t rsa
指定使用RSA加密算法,-b 4096
指定密钥长度为4096位,-C
后面跟的是我们的邮箱地址,用于标识这个密钥对。执行命令后,按提示完成密钥生成过程,可以选择是否设置密码保护私钥。
- 如果我们的系统中已经存在SSH密钥对,这个命令会询我们是否覆盖。如果不希望覆盖,可以生成一个新的密钥对,并在后续步骤中使用新的密钥对。
- 查看公钥:密钥对生成后,公钥通常位于
~/.ssh/id_rsa.pub
(如果我们没有指定其他文件名的话)我们可以使用命令cat ~/.ssh/id_rsa.pub
来查看公钥内容。
二、将公钥添加到远端仓库
登录到远端仓库
添加SSH公钥:在个人账户设置中找到SSH公钥管理页面。点击“New SSH key”或类似按钮,然后粘贴我们在第一步中复制的公钥内容到相应的输入框中我们还可以为这个密钥对起一个可识别的标题。完成后,点击“Add SSH key”或类似按钮,将公钥添到我们到账户中。
三、验证SSH连接
- 在本地终端或命令行中验证SSH连接:切换到我们的项目目录(如果适用),并执行命令
ssh -T git@远端仓库主机名
(例如,对于GitHub,命令是ssh -T git@github.com
)。如果一切设置正确我们应该会看到一条消息,我们明经成功通过SSH连接到远端仓库。
四、使用SSH连接远端仓库
现在,我们成功配置了SSH方式验证,来连接远端仓库我们可以使用常规的Git命令(如git push
、git pull
等)来与远端仓库进行交互,而无需每次都输入用户名和密码。
配置 Git
忽略特殊文件,编写.gitignore
文件
给命令配置别名
git config --global alias.<alias-name> <command>
随后可以使用git <alias-name>
来使用<command>
git config --global --get-all alias
- 这将列出所有已配置的别名及其对应的命令。
标签
- 标签 tag ,可以简单的理解为是对某次 commit 的⼀个标识,相当于起了⼀个别名。
- 例如,在项目发布某个版本的时候,针对最后⼀次
commit
起⼀个v1.0
这样的标签来标识里程碑的意义。
- 例如,在项目发布某个版本的时候,针对最后⼀次
1. 创建标签
- 轻量级标签:
git tag <tag-name>
,其中<tag-name>
是你想要创建的标签名。默认情况下,标签会打在最新提交的commit上。 - 附注标签:附注标签除了包含提交的引用外,还可以包含标签的创建者、创建日期、注释信息等。创建附注标签的命令为
git tag -a <tag-name> -m "tag message"
,其中<tag-name>
是标签名,"tag message"
是标签的注释信息。 - 为特定提交打标签:如果你想要为某个特定的提交打标签,可以使用该提交的哈希值(commit hash)来指定。命令格式为
git tag <tag-name> <commit-hash>
。
2. 查看标签
- 列出所有标签:使用
git tag
命令(或git tag -l
)可以列出仓库中的所有标签。默认情况下,标签是按照字母顺序排列的。 - 查看标签信息:使用
git show <tag-name>
命令可以查看指定标签的详细信息,包括关联的提交信息。 - 过滤标签列表:可以使用
git tag -l '<pattern>'
命令来过滤标签列表,只显示符合特定模式的标签。例如,git tag -l 'v*'
会列出所有以”v”开头的标签。
3. 删除标签
- 删除本地标签:使用
git tag -d <tag-name>
命令可以删除本地的标签。 - 删除远程标签:如果标签已经被推送到远程仓库,并且需要删除,则首先需要删除本地标签,然后使用
git push origin :refs/tags/<tag-name>
命令来删除远程仓库中的标签。其他协作者需要使用git fetch --prune
或git pull --prune
命令来同步更新他们的本地仓库,以删除已经不存在的远程标签。
4. 推送标签到远程仓库
- 推送特定标签:使用
git push origin <tag-name>
命令可以将指定的标签推送到远程仓库。 - 推送所有标签:使用
git push origin --tags
命令可以一次性将所有标签推送到远程仓库。
5. 拉取远程仓库的标签
- 默认情况下,
git fetch
和git pull
命令不会自动获取远程仓库的标签。要获取远程仓库的标签,可以在这些命令后添加--tags
选项,例如git fetch origin --tags
或git pull origin --tags
。
一般设计规范
分支 | 名称 | 适用环境 |
---|---|---|
master | 主分支 | 生产环境 |
release | 预发布分支 | 预发布/测试环境 |
develop | 开发分支 | 开发环境 |
feature | 需求开发分支 | 本地 |
hotfix | 紧急修复分支 | 本地 |
其他知识
开发团队(Dev)和运维团队(Ops)
在传统的IT组织架构中,开发团队(Dev)与运维团队(Ops)之间存在明显的诉求差异:
- 开发团队(尤其是敏捷团队)倾向于追求变化;
- 运维团队则更注重稳定性。
这种差异往往导致双方利益冲突,例如,精益和敏捷团队致力于实现持续交付,而运维团队为确保线上系统的稳定,强调变更控制。这种部门间的隔阂阻碍了IT价值的最大化。为缩小开发与运维之间的差距,需要在文化、工具及实践上进行一系列变革,于是DevOps应运而生。
DevOps(结合了Development和Operations)代表了一种文化、运动或惯例,它强调软件开发人员(Dev)与IT运维技术人员(Ops)之间的沟通与协作。通过自动化软件交付和架构变更流程,DevOps使得软件的构建、测试、发布更加快速、频繁且可靠。其软件开发流程涵盖计划、编码、构建、测试、预发布、正式发布、运维及监控,充分展现了DevOps的强大功能。