Git常用操作
Git 基础
Git 的四个区域(或称工作区域)分别是:
- 工作区(Workspace):也称为“工作目录”,是项目的根目录,其中包含项目的所有文件和子目录。这个区域是我们对项目所做更改的初始地点,即文件的初始版本。
- 暂存区(Index):也称为“缓存区”或“staging area”,是 Git 用于暂存即将被提交到本地仓库的更改的地方。在执行 git add 命令后,文件的当前版本会被复制到暂存区。
- 本地仓库(Repository):包含所有提交的历史版本及其元数据的数据库。在执行 git commit 命令后,暂存区中的更改会被提交到本地仓库中。
- 远程仓库(Remote):与本地仓库类似,但它是存储在网络上的一个或多个 Git 仓库,通常由项目的团队成员使用。在与远程仓库同步之前,本地仓库中的更改不会传输到远程仓库。当您执行 git push 命令时,您将提交的更改推送到远程仓库。在执行 git pull 命令时,您将从远程仓库获取更新并将其合并到您的本地仓库中。
Git 常用命令
创建仓库
|
|
工作区 -> 暂存区
|
|
暂存区 -> 本地仓库
|
|
- –message:缩写为-m,用于在提交时添加提交信息。
- –verbose:缩写为-v,用于在提交时显示变更的详细信息。
- –amend:用于修改上一次提交的信息。
- –all:缩写为-a,用于添加所有已修改或删除的文件,并在提交时忽略未跟踪的文件。
- –no-edit:用于在修改提交信息时不打开编辑器,直接使用上次的提交信息。
非常用 signoff
在使用 Git 进行协作开发时,代码的提交需要有代码贡献者的签署。其中,CLA(Contributor License Agreement,贡献者许可协议)就是一种协议,它规定了贡献者对其提交代码的版权归属、代码授权许可等相关事项。CLA 的目的是保护开源软件的知识产权,防止代码提交者的版权问题引起的纠纷和法律风险。
在 Git 中,–signoff 是一个选项,用于在提交日志中添加 Signed-off-by 行。这个选项的使用场景通常是在参与开源项目的贡献时,通过在提交日志中添加 Signed-off-by 行,表示提交者确认自己已经阅读了项目的 CLA,同意将代码贡献给该项目,并承诺自己对该代码的质量和合法性负责。同时,Signed-off-by 行也提供了代码贡献者的身份信息,方便项目维护者进行代码审核和管理。
- 编写完要提交的代码,并通过
git add
将修改的文件添加到暂存区。 - 使用
git commit
命令提交代码,添加--signoff
参数:git commit --signoff
- 根据提示,输入本次提交的信息。
- 提交成功后,可以通过
git log
命令查看到 Signed-off-by 行的信息:
|
|
Signed-off-by 行必须要包含提交者的姓名和 email 地址,例如上面的例子中的 “Kira [email protected]”。如果在 Git 的全局配置中没有配置 email 地址,也可以手动指定:git commit --signoff --author="Kira <[email protected]>"
非常用 gpg-sign
--gpg-sign
是 Git 命令的一个选项,用于在提交时进行 GPG 签名。它可以确保提交的内容在传输和存储过程中不会被篡改,增强了提交的安全性。当代码库需要确保提交内容的完整性和真实性时,可以使用 --gpg-sign
选项。
使用 --gpg-sign
选项需要在本地配置好 GPG 密钥对,具体步骤如下:
- 生成 GPG 密钥对:使用命令
gpg --gen-key
生成 GPG 密钥对,并设置密码和用户名等信息。 - 将 GPG 公钥添加到代码库:使用命令
gpg --armor --export <key-id>
导出 GPG 公钥,并将公钥添加到代码库的 GPG 密钥列表中。 - 配置 Git 选项:使用命令
git config --global user.signingkey <key-id>
配置 Git 选项,以便在提交时使用正确的密钥进行签名。 - 提交代码并进行 GPG 签名:在提交时使用
--gpg-sign
选项进行签名,例如git commit --gpg-sign
。
在以上步骤完成后,提交代码时会要求输入 GPG 密码进行签名,以确保提交内容的完整性和真实性。
提交规范
为什么使用常规提交?
- 便于自动化版本号和发布流程的管理:使用规范的提交消息可以轻松自动化版本号的生成和发布流程的管理。例如,基于规范的提交消息可以自动检测是否应该发布一个新版本,以及新版本的版本号应该是多少。
- 提高代码可读性和可维护性:使用规范的提交消息可以提高代码的可读性和可维护性。规范的提交消息使得查找某个提交的目的、影响范围和处理方式变得更加容易。这对于团队协作和维护项目历史记录非常有帮助。
- 改进提交消息的一致性和可靠性:规范的提交消息可以帮助确保提交消息的一致性和可靠性。提交消息按照统一的模式编写可以避免模糊不清或不一致的消息,并且可以帮助开发人员更好地描述提交的目的和内容。
- 促进开发者的交流和理解:规范的提交消息可以促进开发者之间的交流和理解。通过使用规范的提交消息,开发人员可以更好地沟通并理解彼此的工作,从而帮助团队更好地合作开发。
在 Angular Conventional Commit 的提交规范中 message 的格式如下:
|
|
这是 Conventional Commits 规范中标准的提交消息格式,各部分的含义如下:
<type>
:表示本次提交的类型,例如 feat(新功能)、fix(修复 bug)、docs(文档变更)、style(代码风格变更)、refactor(重构代码)等。该字段是必填的。[optional scope]
:表示本次提交的范围,例如模块、文件、类等。该字段是可选的。<description>
:表示本次提交的简短描述,最好能够清晰地描述本次提交的目的和作用。该字段是必填的。[optional body]
:表示本次提交的详细说明,可以包含更详细的描述、操作流程、注意事项等内容。该字段是可选的。[optional footer]
:表示本次提交的元数据,包括关联的 issue、重大变化说明、不兼容变化说明等内容。该字段是可选的。
本地仓库 -> 远程仓库
|
|
push 冲突
Git 冲突通常发生在团队合作时,多个成员在同一时间修改同一行代码,当他们尝试将修改提交到 Git 仓库时,就会发生冲突。处理冲突的流程如下:
- 使用 git pull 命令将远程仓库的最新更改合并到本地仓库中。如果远程仓库和本地仓库都对同一文件进行了更改,则会自动发生冲突。
- 找到冲突文件:如果在执行上一步命令时出现错误,则需要手动查找冲突文件。Git 会在冲突文件中标记出冲突的地方,你可以通过以下命令查找冲突文件:
git status
这将会列出有冲突的文件。
|
|
- 您需要手动编辑文件并删除冲突标记,保留您需要的更改。在完成解决冲突后,保存并关闭文件。
- 使用 git commit 命令提交更改。在提交消息中,您可以简要描述您所做的更改和如何解决冲突。
- 使用 git push 命令将更改推送到远程仓库。
- 如果在上述步骤中出现问题,您可以使用
git merge --abort
命令取消合并,并尝试重新合并更改。
查看 commit
|
|
--stat
:显示简要的统计信息,如修改的文件、插入的行数和删除的行数等。--graph
:使用 ASCII 字符画的方式展示提交历史,可以清晰地看到不同分支的合并情况。--decorate
:在提交历史中显示 tag 和分支等引用的名称。--all
:展示所有分支的提交历史。--patch
:缩写为-p,显示每个提交的具体变更内容。--oneline
:以单行的形式展示提交历史。--pretty
:可以指定不同的格式来展示提交历史,如--pretty=format:"%h - %an, %ar : %s"
,这个命令会显示每个提交的简短 SHA-1 值、作者、提交时间和提交说明。
查找 commit
|
|
合并 commit
在 Git 中,我们可以针对同一个任务由多次提交,但是多个提交会让版本管理显得比较乱。为了解决这个问题,可以使用 git rebase
命令来合并多个 commit 为一个。
- 使用
git rebase -i <commit>
命令来打开交互式 rebase 窗口,然后将需要合并的 commit 的前面的命令改为 squash 或 s。(其中的顺序和 git log 相反) - squash 表示该 commit 将会被合并到前一个 commit 中,pick 表示该 commit 会被保留。
- 保存并退出后,需要重新编辑合并后的 commit 信息,即输入合并后的 commit message,保存后即完成 commit 的合并。
需要注意的是,使用 git rebase 命令合并 commit 时,需要注意保持提交顺序不变,否则可能会造成代码冲突或者其他问题。另外,如果合并后的 commit 包含了多个功能或者修改,建议将其拆分成多个独立的 commit,以便更好地进行版本管理。
修改 commit
修改 commit 的 message
如果我们想修改之前的某个 commit message,可以使用 git rebase 命令。
- 首先,输入
git rebase -i <commit-hash>
命令,来进入交互式编辑模式。 - 在编辑窗口中,找到需要修改的 commit,将对应的
pick 命令修改为 reword
,并保存退出。 - 之后会弹出一个编辑器窗口,让我们编辑 commit message,修改完成后保存并退出。
- 如果需要修改多个 commit message,则需要重复这个过程。
- 最后,如果所有的 commit 都已经 push 到远程仓库,我们需要使用
git push --force
强制推送到远程仓库。
修改 commit 的内容
当我们在历史提交中发现某个文件的修改不完整时,可以使用 git rebase 的 edit 命令进行修改。
- 首先,我们需要使用 git rebase 命令进入交互式界面,然后将需要修改的 commit 前的
pick 命令改为 edit
。 - 接下来,git rebase 会停止工作,以便我们可以编辑文件和 commit message。
- 在编辑完毕后,我们可以使用
git commit --amend
命令来修改提交内容,然后使用git rebase --continue
命令继续进行之后的 edit 命令。 - 如果修改前的所有 commit 都已经推送到远程仓库,我们需要使用
git push --force
命令来强制推送到远程仓库。
回滚操作
工作区
本地仓库检出内容,然后覆盖掉工作区的内容,即丢弃了本地所有的修改
|
|
内容已经存在工作区了,但是尚未提交到暂存区,即是 untracked 的内容,我们可以使用
|
|
暂存区
放弃本地的所有修改
|
|
本地仓库
假设你在本地对代码做了一些修改,但尚未将这些修改推送到远程仓库。当你想要撤销这些修改时,可以使用 git reset 命令。
首先要知道的是,git reset 命令有三个参数:
- –soft:只回滚提交历史,不改变暂存区和工作目录的内容
- –mixed:回滚提交历史和暂存区的内容,但不改变工作目录的内容(默认参数)
- –hard:回滚提交历史、暂存区和工作目录的所有内容
假设远程仓库的最新提交是 6ff5433b,而你在本地已经有三个新的提交。你想要回滚这些提交并覆盖本地工作区的内容,然后将这些修改推送到远程仓库。
你可以使用git reset --hard HEAD~3
命令,将 HEAD 指针回滚三个版本,使用这些版本的代码覆盖本地工作区的内容。这样,你的本地仓库就恢复到了远程仓库的状态。最后,使用git push origin main
命令将你的修改推送到远程仓库。
需要注意的是,git reset --hard
命令是不可逆的,因此在执行该命令之前,一定要确保你理解了它的工作原理,并且做好必要的备份。如果你想要保留这些修改但不想将其推送到远程仓库,可以考虑使用git stash
命令。
远程仓库
没有基于此提交的修改
如果没有其它同事基于我们的 commit 做修改的话,使用git revert
命令是比较好的选择,而不是git reset
命令。因为git reset
会删除 commit 记录,对于其它同事的修改也会产生影响。
举个例子,假设我们有三个 commit,现在想回退 3f5313b
这个分支:
|
|
需要执行以下步骤:
git revert 3f5313b
- 如果有冲突需要解决冲突 或
git revert --abort
取消本次回退 git commit
:提交修改git push
:push 到远程仓库
有基于此提交的修改
git checkout -b reset_to_5ff5433b 5ff5433bd1fe4
:从 5ff5433bd1fe4 处创建分支。git show 9d531db98276
:9d531db98276 为最新的提交,查看 main 分支上的其它同事的提交,把他的修改在新分支上再修改一遍。git commit –a –m “reverted 5ff5433b”
:提交git checkout main
:切换到 main 分支。git merge reset_to_5ff5433b
:合并修改。git push
:推送到远程仓库
删除文件
正常删除文件
git rm -rf test.go
:删除当前目录下的test.go
文件,并将此修改标记为待提交的更改。git commit -m "remove test.go"
:将此次删除提交到本地仓库,并使用 “remove test.go” 作为提交信息。git push
:将本地仓库的修改推送到远程仓库,以便其他人或其他机器可以访问这些更改。
敏感文件删除,比如 RSA 的私钥或生产环境数据库密码等
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch src/main/resources/config/application-test.yml' --prune-empty --tag-name-filter cat -- --all
git filter-branch
: 这个命令可以重写 Git 仓库的历史记录。它提供了多个选项,可以对提交的内容进行修改、删除、重命名等操作。--force
: 强制执行操作。--index-filter 'git rm --cached --ignore-unmatch src/main/resources/config/application-test.yml'
: 用于指定一个索引过滤器。这个索引过滤器会在每个提交中删除src/main/resources/config/application-test.yml
这个文件(或者文件夹,如果使用了-r
参数)。--prune-empty
: 这个选项会在过滤器执行后删除空的提交。--tag-name-filter cat
: 这个选项会用 cat 命令来处理标签名。这个选项的作用是确保所有标签都被重写,以便与过滤后的提交相匹配。-- --all
: 这个选项表示应用以上所有选项到所有分支。
git push origin --force --all
: 强制推送所有本地分支的修改到远程仓库。git push origin --force --tags
: 强制推送所有本地标签的修改到远程仓库。
Git stash
Git stash 可以用来暂存未提交的工作进度,并将当前工作目录还原到上一次提交的状态。这里是使用 Git stash 的一个典型流程:
-
使用
git stash push
将当前未提交的工作进度暂存起来。 -
可以使用
git stash list
命令查看当前所有的 stash 记录。 -
使用
git stash apply
命令来恢复最新的 stash 记录。如果有多个 stash 记录,可以使用git stash apply stash@{n}
命令来恢复指定的 stash 记录。 -
如果要暂存所有的变更,可以使用
git stash --all
命令。 -
使用
git stash drop
命令来删除最新的 stash 记录。git stash drop stash@{X}
:删除 Git stash(缓存)中序号为 X 的存储修改内容。- 如果要删除所有的 stash 记录,可以使用
git stash clear
命令(慎用)。
-
使用
git stash pop
命令可以恢复最新的 stash 记录,并删除该记录。 -
使用
git stash show --text
命令可以查看 stash 记录的内容。如果需要查看更多信息,可以使用git stash show stash@{n} --text
命令来查看指定的 stash 记录。
git stash save 和 git stash push 区别?
- 在早期版本的 Git 中,使用
git stash save
命令来保存工作区的修改,但在 Git 2.13 版本中,git stash save
已经被废弃,建议使用git stash push
命令来代替。 - 实际上,
git stash push
命令和git stash save
命令的作用是一样的,都是将当前工作区的修改保存到一个栈中。区别在于,git stash push
命令可以通过选项更加灵活地控制保存的内容。- 例如,可以使用
--include-untracked
选项来将未跟踪的文件也一同保存,使用--patch
选项来交互式选择要保存的修改等。同时,git stash push
命令也可以使用-m
选项来添加一条消息,以便后续更好地识别保存的内容。
- 例如,可以使用
- 综上,虽然
git stash save
命令在一些老版本的 Git 中仍然可以使用,但建议使用git stash push
命令来代替,并结合选项更加灵活地控制保存的内容。
查看修改
|
|
Git submodule
|
|
Git Branch
|
|
分支管理
Git 的分支管理涉及到以下分支:
main
:作为稳定分支,仅接受已经 review 过且通过测试的代码,可用于生产环境部署。develop
:主要开发分支,用于进行持续集成和 code review,也是 bug 修复和新功能开发的基础分支。feature
:每个功能或变更请求都可以基于 Develop 分支拉取一个 Feature 分支,用于开发、review 和测试,测试通过后将该分支合并到 Develop 分支。hotfix
:紧急修复分支,主要用于从 Main 分支拉取代码修复紧急问题并合并到 Develop 和 Main 分支。release
:预发布分支,用于特定版本的系统测试,测试通过后可合并到 Main 分支并打上对应的版本号。bug
:用于修复 bug 的分支,定位并解决后将该分支合并到 Develop 和 Release 分支,并进行回归测试,回归测试通过后关闭该 bug。
Git Tag
Git 的 tag 是用来标记特定的 commit,以便于后续的查找和发布等操作。在一个项目中,可能存在多个 tag,每个 tag 可以对应不同的版本或者里程碑。
|
|
Git bisect
git bisect
命令可以帮助我们找到引入问题的提交。使用该命令需要先指定一个知道没有问题的提交和一个已知有问题的提交,然后 Git 会逐步缩小问题引入的范围,直到找到引入问题的提交为止。
- 确定一个已知没有问题的提交和一个已知有问题的提交,例如:
|
|
注意,good
和 bad
都可以指定提交的 SHA-1 值,也可以使用分支名、tag 名等来表示。
- Git 会自动切换到一个中间的提交,并等待你测试该提交是否有问题。你需要执行一些测试代码来判断该提交是否有问题,然后告诉 Git 结果:
|
|
- Git 根据你的测试结果自动切换到另一个中间的提交,然后你需要再次测试该提交并告诉 Git 结果。这个过程会一直进行下去,直到找到引入问题的提交为止。
- 如果你测试了很多次后无法确定问题引入的提交,可以使用
git bisect reset
命令结束二分查找,并返回到起始状态。
Git worktree
git worktree
是 Git 的一个功能,可以让你在同一个本地仓库中创建多个工作区,每个工作区都可以指向仓库的不同分支或提交。这个功能可以方便地进行多个任务的并行开发,而不必切换分支或创建多个本地仓库。
比如:通过 git worktree
可以方便地创建多个工作区,每个工作区可以指向不同的分支或提交,从而让你能够在同一个本地仓库中并行开发不同的功能或修复不同的问题。
|
|