基本操作
工作流
常见的 Workflow 有三种情况:
单分支
一般见于个人使用场景, 所有工作内容均在主分支进行和完成。
C----C----C----C----C---- (main)
Github Flow
一般见于小型团队使用场景, 每项工作内容均在新建的针对性的短期分支 (如 feture
、bug-fix
等) 进行, 并最终合并到主分支。
C---C---C C (feature/bugfix)
/ \ / \
C---------------C------C---- (main)
Git Flow
一般见于各类团队使用场景, 分支类型根据生命周期分为长期分支和短期分支:
-
长期分支包括:
-
主分支 (
main
/master
), 仅包含删节的提交记录和节点 -
开发分支 (
dev
/devlop
/stage
), 由主分支fork
产生, 将包含项目的完整提交记录和节点, 最终合并入主分支
-
-
短期分支包括:
-
新增功能分支 (
feature-*
), 由开发分支fork
产生, 最终合并入开发分支 -
缺陷修复分支 (
bugfix-
/hotfix-
), 由开发分支fork
产生, 最终合并入主分支与开发分支 -
版本发布分支 (
release-*
), 由开发分支fork
产生, 可以进行缺陷修复、文档生成等发布相关变动, 完成后合并入主分支, 并合并回开发分支 -
本地临时分支
-
长期分支并不用于日常维护, 仅当临时的短期分支中的变更完成后, 才会依次合并入长期分支。
C-----C (feature/bugfix)
/ \
/ \ C (release)
/ \ / \
C--------------C \ (dev/develop/stage)
/ \
C---------------------------C---- (main/master)
如何初始化当前目录为 Git 仓库
git init
如何添加远程仓库
git add remote https:/domain.com/repo.git
如何查看远程仓库信息
git remote -v
git remote show origin
如何克隆仓库
git clone https://domain.com/repo.git
git clone https://domain.com/repo.git path/to/folder/
如何查看 Git 仓库配置信息
git config -l
如何查看全局 Git 配置信息
git config --global -l
如何记住账号密码等认证信息
git config credential.helper cache
git config credential.helper store
如何更改默认编辑器
git config --global core.editor "nano"
如何全局配置记住认证信息
git config --globan credential.helper cache
git config --global credential.helper store
如何取消某条 Git 仓库配置
git config unset config-label
例如取消记住认证信息:
git config unset credential.helper
如何取消某条 Git 全局配置
git config --global unset config-label
如何暂存文件
git add path/to/file.ext
git add .
git add --all
git add *.txt
如何在暂存文件时进行对比选择
git add -p
如何取消暂存文件
git reset path/to/file.ext
git reset *
如何撤销修改
如何撤销未暂存文件的修改
git checkout path/to/file.ext
如何撤销已暂存文件的修改
git reset --hard path/to/file.ext
git reset --hard HEAD
如何查看 Git 仓库状态
git status
如何对比文件修改信息
git diff
git diff path/to/file.ext
git diff --staged
如何提交修改
git commit
git commit -m "commit message here"
如何设置提交信息模板
git config commit.template /absolute/path/to/template/file
git config commit.template /relative/path/from/repository/root
如何撰写一条合适的提交记录
一条合适的提交记录应该包含:
type: subject
body (optional)
footer (optional)
Type/类型
-
feat
- 一个新增功能 -
fix
- 一个缺陷修复 -
docs
- 文档变动 -
style
- 样式调整 -
refactor
- 非缺陷修复和新增功能的代码变动 -
test
- 测试相关变动 -
chore
- 更新编译构建、项目配置等
Subject/主题
简要的描述修改内容, 一般在 50 个字符以内较好。
Body/详情
这一部分用于解释你进行的修改和修改的原因等内容。当然, 并非所有的提交都需要这一部分进行说明。
在 Body
与 Subject
之间必须要留有一行空行。同时, Body
部分每一行应限制在 72 个字符以内。
Footer/脚注
这一部分也是可选的, 一般在你使用了缺陷追踪工具时会在这里添加和引用缺陷 ID 等信息。
示例
fix: crash when click on the home button
Every time when user click on the home button, the app crash. This bug no longer exists.
Resolves: #123
See also: #456, #789
如何查看提交记录
git log
git log --oneline
git log --graph
如何查看所有分支的提交记录
git log --all
如何查看远程仓库的提交记录
git log origin/main
如何修正最近一次的提交信息
git commit --amend
如何修正最近一次的提交信息并添加新文件
git commit --amend -a
如何回滚提交
git revert HEAD
git revert commit-id-here
如何在 Git 中重命名文件
git mv oldname.ext newname.ext
如何在 Git 中删除文件
git rm path/to/file/or/folder
git rm --cached path/to/file/or/folder
如何推送到远程仓库
git push
如何强制推送
git push -f
如何从远程仓库拉取并自动与本地合并
git pull
如何配置偏离分支合并策略
git config pull.rebase false
git config pull.ff only
如何从远程仓库拉取但不自动与本地合并
git fetch
如何查看分支列表
git branch
git branch -r
如何创建新本地分支
git branch branch-name-here
如何重命名分支
git branch -m old-branch-name new-branch-name
如何切换分支
git checkout branch-name-here
如何创建并切换到新本地分支
git checkout -b branch-name-here
如何将本地新分支推送到远程仓库
git push -u origin branch-name-here
如何删除分支
如何删除本地分支
git branch -d branch-name-here
如何删除远程分支
git push --delete origin branch-name-here
如何合并其它分支到当前分支
git merge branch-name-here
如何终止正在进行的合并
git merge --abort
如何新建标签
git tag 1.0.0
如何将标签推送到远程仓库
git push --tags
如何删除标签
如何删除本地标签
git tag -d 1.0.0
如何删除远程仓库的标签
git push --delete tag 1.0.0
如何对提交记录进行变基: 遴选、压平、编辑等操作
选择要操作的提交记录的前一条记录进行变基:
git rebase -i previous-commit-id
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
此操作会将指定
commit-id
后 (不包括该commit-id
所对应的提交记录) 所有提交记录提供给用户进行遴选、压平、编辑等操作。
Warning
|
请注意, 除非个人使用, 否则不要用于操作公开和远程的分支、提交记录。 |
例如, 我们当前有如下提交记录:
git log --oneline
612f2f7 This commit should not be squashed
a3fb05d This commit should be squashed
d84b05d This commit should be updated
36d15de Rebase from here
17692d1 Did some more stuff
e647334 Another Commit
2e30df6 Initial commit
此时假设我们希望的需求是:
-
保留最新的
612f2f7 This commit should not be squashed
记录 -
但将
a3fb05d This commit should be squashed
压平后合并入d84b05d This commit should be updated
-
并更新为新的日志信息
那么我们应当选取其前一条记录, 也即 36d15de Rebase from here
, 进行变基操作:
git rebase -i 36d15de
在出现的编辑器中, 提交记录的顺序与 git log
中的顺序是相反的。
此时根据我们的需求, 我们应当:
-
保持最新的
612f2f7 This commit should not be squashed
记录为pick
状态 -
修改要被合并的
a3fb05d This commit should be squashed
为squash
/s
状态 -
修改其合并入的
d84b05d This commit should be updated
为edit
/e
状态-
(如果不需要更新此处的日志信息, 则修改状态为
pick
/p
即可)
-
然后保存。
edit d84b05d This commit should be updated
squash a3fb05d This commit should be squashed
pick 612f2f7 This commit should not be squashed
此处由于我们标记了 edit
状态, 保存后会要求执行 git commit --amend
命令编辑日志信息, 我们将根据需求修改日志信息, 例如 A updated commit message
, 并保存。
再次查看日志, 会发现记录 a3fb05d This commit should be squashed
已经被压平合并到其前一条记录中, 且该记录的日志信息也已经变更:
git log --oneline
612f2f7 This commit should not be squashed
d84b05d A updated commit message
ac60234 Yet another commit
36d15de Rebase from here
17692d1 Did some more stuff
e647334 Another Commit
2e30df6 Initial commit
如何对分支进行变基
git rebase base-branch-name-here
如何终止变基操作
git rebase --abort
如何继续变基操作
git rebase --continue
如何区分合并与变基
如何进行打包发布
git archive --format=tar --prefix=proj-1.2.3/ HEAD
如何同时操作多个 Git 仓库
例如使所有子目录下的 Git 仓库统一执行拉取操作:
find . -type d -exec git --git-dir={}/.git --work-tree=$PWD/{} pull origin master \;
操作实例
一般流程
准备工作
接手新项目后, 首先要在本地安装 git
工具、客户端等工具, 例如:
sudo apt install git
sudo yum install git
sudo dnf install git
sudo pacman -Sy git
克隆项目仓库到本地:
git clone https://domain.com/path/to/repo.git
然后进入克隆好的本地仓库:
cd repo
初始化
如果是全新构建的项目, 先创建开发分支 stage
并推送到服务器:
git checkout -b stage
此时我们将处于 stage
分支中。
git push -u origin stage
分支切换
进入新克隆的项目时我们默认处于主分支中, 一般为 master
或 main
分支。
根据团队要求的不同, 我们可能需要进行分支切换和创建。通常来说, 我们会切换到 dev
/devlop
/stage
分支, 并基于该分支创建新的短期工作分支:
git checkout stage
git checkout -b feature-0206
此时可以在 feature-0206
分支开始工作了。
提交变动
待工作告一段落时, 首先需要对修改的文件进行添加暂存, 最简单的是全部暂存:
git add --all
如果需要暂存特定文件:
git add path/to/file.txt
git add path/*.txt
如果修改的内容较多, 可以进行对比:
git diff path/to/file.txt
并选择其中部分进行暂存:
git add -p path/to/file.txt
如果意外暂存了错误的文件, 可以对其状态进行重置:
git reset path/to/file.txt
如果不需要暂存某文件, 可以通过增加 .gitignore
文件进行忽略, 或者:
git rm path/to/file.txt
接下来, 需要本地提交这些暂存:
git commit -m "some commit message here"
通过反复暂存和提交后, 所有修改均已在本地提交, 此时应检查日志:
git log
你将看到类似下面的结果:
commit 655acf96e613aa38a25c62a969cee56d2ccf9cdd (HEAD -> master)
Author: Ezra <[email protected]>
Date: Tue Feb 6 14:16:47 2022 +0800
API doc improvements
commit e4b480e2446570d2aa32543c930bd37121ae9dc9
Author: Ezra <[email protected]>
Date: Tue Feb 6 14:16:17 2022 +0800
change api document
commit 85d81525fc07db28de1304b4743f8bea1a300db8
Author: Ezra <[email protected]>
Date: Tue Feb 6 13:51:18 2022 +0800
API
commit ccf8ad5c9758c9d07212ae7cf11aa2bc5ffc4c8d
Author: Ezra <[email protected]>
Date: Tue Feb 6 13:50:38 2022 +0800
dev files
commit 71d35b059bfd1951e9a2310eadda12c4f26a3d61
Author: Ezra <[email protected]>
Date: Tue Feb 6 13:50:07 2022 +0800
README
commit 18031d7cf833118200f9aae247680bdb91a10f87
Author: Ezra <[email protected]>
Date: Tue Feb 6 13:47:57 2022 +0800
init
遴选压平
在此示例中, 最近的三条提交记录均为对 API.md
文件的同一类型的修改, 因此我们希望将如下三条记录合并为一条:
-
655acf96e613aa38a25c62a969cee56d2ccf9cdd API doc improvements
-
e4b480e2446570d2aa32543c930bd37121ae9dc9 change api document
-
85d81525fc07db28de1304b4743f8bea1a300db8 API
这时我们需要找到前一条记录, 假设为 ccf8ad5c9758c9d07212ae7cf11aa2bc5ffc4c8d dev files
, 执行变基操作:
git rebase -i ccf8ad5c9758c9d07212ae7cf11aa2bc5ffc4c8d
执行上述指令后会出现编辑器:
1 pick 85d8152 API
2 pick e4b480e change api document
3 pick 655acf9 API doc improvements
4
5 # Rebase ccf8ad5..655acf9 onto ccf8ad5 (3 commands)
6 #
7 # Commands:
8 # p, pick <commit> = use commit
9 # r, reword <commit> = use commit, but edit the commit message
10 # e, edit <commit> = use commit, but stop for amending
11 # s, squash <commit> = use commit, but meld into previous commit
12 # f, fixup <commit> = like "squash", but discard this commit's log message
13 # x, exec <command> = run command (the rest of the line) using shell
14 # b, break = stop here (continue rebase later with 'git rebase --continue')
15 # d, drop <commit> = remove commit
16 # l, label <label> = label current HEAD with a name
17 # t, reset <label> = reset HEAD to a label
18 # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
19 # . create a merge commit using the original merge commit's
20 # . message (or the oneline, if no original merge commit was
21 # . specified). Use -c <commit> to reword the commit message.
22 #
23 # These lines can be re-ordered; they are executed from top to bottom.
24 #
25 # If you remove a line here THAT COMMIT WILL BE LOST.
26 #
27 # However, if you remove everything, the rebase will be aborted.
28 #
由于我们要进行三条记录的合并, 因此将编辑器中第二行和第三行的 pick
改为 squash
或 s
后保存:
1 pick 85d8152 API
2 s e4b480e change api document
3 s 655acf9 API doc improvements
这一操作意味着, 我们将遴选第一条记录, 然后将第二条和第三条记录压平, 以便合并为同一条。
保存后, git
还会弹出新的编辑器, 要求我们对提交信息进行编辑:
1 # This is a combination of 3 commits.
2 # This is the 1st commit message:
3
4 API
5
6 # This is the commit message #2:
7
8 change api document
9
10 # This is the commit message #3:
11
12 API doc improvements
13
14 # Please enter the commit message for your changes. Lines starting
15 # with '#' will be ignored, and an empty message aborts the commit.
16 #
17 # Date: Tue Feb 8 13:51:18 2022 +0800
18 #
19 # interactive rebase in progress; onto ccf8ad5
20 # Last commands done (3 commands done):
21 # squash e4b480e change api document
22 # squash 655acf9 API doc improvements
23 # No commands remaining.
24 # You are currently rebasing branch 'master' on 'ccf8ad5'.
25 #
26 # Changes to be committed:
27 # new file: API.md
28 #
此处我们根据实际情况对提交记录的信息进行编辑并保存, 当然, 也可以直接保存:
[detached HEAD 7a713af] API doc improvements
Date: Tue Feb 8 13:51:18 2022 +0800
1 file changed, 7 insertions(+)
create mode 100644 API.md
Successfully rebased and updated refs/heads/master.
看到上面的信息时, 我们的变基操作已经成功, 接下来, 再次查看日志进行确认:
git log
commit 7a713af4d153bd5cb1a74f83161e496c5d4442a6 (HEAD -> master)
Author: Ezra <[email protected]>
Date: Tue Feb 8 13:51:18 2022 +0800
API doc improvements
commit ccf8ad5c9758c9d07212ae7cf11aa2bc5ffc4c8d
Author: Ezra <[email protected]>
Date: Tue Feb 8 13:50:38 2022 +0800
dev files
commit 71d35b059bfd1951e9a2310eadda12c4f26a3d61
Author: Ezra <[email protected]>
Date: Tue Feb 8 13:50:07 2022 +0800
README
commit 18031d7cf833118200f9aae247680bdb91a10f87
Author: Ezra <[email protected]>
Date: Tue Feb 8 13:47:57 2022 +0800
init
可以看到, 我们已经将最近的三条记录合并为同一条。
Warning
|
注意: 此压平变基操作仅适用于还未推送到服务器的本地提交记录, 如果你的操作涉及到远程服务器和其他项目成员, 可能会造成非常严重的不良后果! |
拉取变更
现在, 我们可以拉取远程仓库的变更到本地:
git pull
依照 git
提示, 解决出现的冲突 (如果有)。
合并推送
接下来, 你可能需要根据实际请进行以下某一项操作:
-
合并到
dev
/devlop
/stage
分支后推送到远程分支 -
直接推送修改到远程服务器
第一种情况下, 首先需要切换到 dev
/devlop
/stage
分支, 然后进行合并:
git checkout stage
git merge feature-0206
你需要根据提示解决冲突 (如果有), 之后便可以进行推送了:
git push
第二种情况下, 直接推送当前的 feature-0206
分支到远程仓库:
git push -u origin feature-0206
Note
|
当然, 你也可以选择使用 |
下一次
在下次一次开始工作时, 切记先进行拉取操作后再根据情况进行新建分支、切换分支等工作。
强制推送
在某些特殊情况下 (例如你在使用属于你个人的私有仓库), 如果你真的需要对已经推送到服务器的提交记录进行遴选、压平和变基操作, 你可以强制推送你的变更到服务器:
git push -f
当然, 很多仓库服务器的默认设置是不允许强制推送的, 你提前需要在管理端开启。