git的基本功工作方式包括以下几个:
- 主分支: master
- 开发分支: develop
- 提测分支: relase 如:relase/V2.0.0
新功能开发,develop 分支检出一个 feature 分支开发(合并后可删除)
bug 修复,develop 分支检出一个 hotfix 分支开发(合并后可删除)
提测从 develop 检出一个 relase 分支提测,发布后 relase 分支合并到 master
若前端项目只有一个人负责,可以直接在 develop 开发,使用 Git 工作流规范,可以推进持续集成的统一建设,不会影响产品的持续发布。
下面的内容包括了 Git 常用的命令,以及各命令或详或简但有必要的解释说明,其中也包括了很多相关的引用链接用于扩展阅读。
推送和拉取
推送:
# 推送远程,并设置当前分支的 upstream 为 main,设置之后每次推送当前分支只需要 git push 即可
git push -u origin main
# 推送远程至 upstream,如果没有设置,在 git 2.0 之前,所有同名分支被推送,git 2.0 之后,报错
git push
# 强制推送
git push -f
# 推送至远程,但是设置远程分支名称
git push origin hehe:haha
拉取:
git checkout -b <local-branch> origin/<remote-branch> # 拉取远程指定分支并检出
git push
的默认行为:默认行为根据 git 配置里的push.default
的值决定,在 git 2.0 之前的默认值是matching
,之后的是simple
,所以在 2.0 之后如果没有设置上游分支 upstream 就会报错。
push.default
的可选值:
- nothing,禁止
git push
,必须显式指定推送分支,比如git push origin master
;
- current,把本地分支推送至远程,远程分支名和本地分支名相同;
- upstream,推送到 upstream 上;
- tracking,同上一个
upstream
,不推荐使用;
- simple,推送到 upstream 上,但是要保证 upstream 的分支名和本地分支名相同;
- matching,推送所有的本地和远程相同名称的分支。
设置local
(仓库)级别的默认推送行为:
git config push.default nothing
分支
查看分支:
# 查看所有分支
git branch -a
# 查看本地分支
git branch
# 查看远程分支
git branch -r
删除分支:
# 删除本地分支(删除不了未合并过的分支)
git branch -d feature-album
# 删除未合并过的本地分支
git branch -D feature-album # 大写的 D
# 删除远程分支
git push origin --delete feature-album # 第一种方法
git push origin :refs/branch/feature-album # 第二种方法,这种方法适用在,分支名和标签名相同时,执行第一种方法会冲突报错,则使用这个方法,因为第一种方法也可以用来删除标签
检出远程分支:
git checkout -b <local-branch> origin/<remote-branch> # 拉取远程指定分支并检出
重命名分支(本地):
# 重命名当前分支
git branch -m <new_name> # -m 是 --move 短格式
# 重命名指定分支
git branch -m <old_name> <new_name>
# 在大小写无感的文件系统中重命名分支
git branch -M <New_Name> # 如果不是用 -M,会报错 fatal: 一个分支名 'new_name' 已经存在
重命名分支(本地):
# 重命名当前分支
git branch -m <new_name> # -m 是 --move 短格式
# 重命名指定分支
git branch -m <old_name> <new_name>
# 在大小写无感的文件系统中重命名分支
git branch -M <New_Name> # 如果不是用 -M,会报错 fatal: 一个分支名 'new_name' 已经存在
克隆
git clone git@github.com:wswmsword/git-learning.git
克隆所有分支,并切换到指定分支:
git clone -b main git@github.com:wswmsword/git-learning.git # 克隆所有分支,并切换到 main
克隆指定分支:
git clone -b main --single-branch git@github.com:wswmsword/git-learning.git # 克隆 main
克隆指定文件夹(git 2.25+ (Q1 2020)):
mkdir git-sparse-checkout && cd git-sparse-checkout # 创建并进入文件夹
git init -q # 静默初始化
git remote add origin git@github.com:wswmsword/git-learning.git
git sparse-checkout set assets # 设置指定文件夹,文件夹路径为 assets
git pull origin main
ls # assets
git sparse-checkout disable # 关闭 sparse-checkout
旧版本的 git 克隆指定文件夹:
mkdir git-sparse-checkout-old && cd git-sparse-checkout-old
git init -q
git remote add origin git@github.com:wswmsword/git-learning.git
git config --global core.sparseCheckout true
echo "assets" >> .git/info/sparse-checkout
git pull origin main
提交
暂存:
git add . # 暂存所有改动文件
git add -e <filename> # 把一个文件里的部分行移至暂存,暂存一部分
git add -p <filename> # 交互式,执行后将输出选项供选择,选择 e 可以暂存一部分
git add -u # 除未跟踪的文件外,把所有文件暂存
git add --ignore-removal . # 除已删除的文件外,暂存所有的文件
提交:
# 提交,添加信息
git commit -m "junior commit"
# 提交指定文件(这里的文件是 file-abc)
git commit file-abc -m "add single file"
# 提交,打开默认编辑器编辑提交信息
git commit
# 暂存已跟踪的文件,同时提交(省略了 git add 命令,但是这里只能暂存已跟踪文件)
git commit -am "junior commit"
# 提交,打开默认编辑器编辑提交信息,包含 diff 信息
git commit -v
# 提交,允许空提交信息
git commit --allow-empty-message
# 修改上一次提交
git commit --amend -m "better message was committed"
# 打开默认编辑器,修改上次提交信息
git commit --amend
# 修改上次提交的邮箱
git commit --amend --author "New Authorname <authoremail@mydomain.com>"
检出某一条提交记录:
git checkout <commit-hash>
合并
# 指定分支合并到当前分支
git merge feature-album
# 安全合并
git merge --no-ff --no-commit my-branch # --no-commit 不自动提交,--no-ff 不使用 fast-forward(快进)
# 合并的时候把一个分支合并成一条记录
git merge --squash feature-album
# 合并分支不提交记录
git merge feature-album --no-commit
# 终止合并(解决冲突的阶段)
git merge --abort
合并其它分支的一个文件:
git checkout --patch testing-merge-file features/album/audio-formats # 合并 testing-merge-file 分支的 features/album/audio-formats 文件
执行完上面的命令后进入优选项的交互界面,选择 e(manually edit the current hunk),进行文件的冲突编辑,最后保存,文件会在暂存区内。
如果命令中不加--patch
,执行完命令的行为是当前分支的文件被指定分支的文件覆盖:
git checkout testing-merge-file features/album/audio-formats # 当前分支的文件 features/album/audio-formats 被 testing-merge-file 分支的覆盖
关于git merge <branch>
在fast-forward
情况下和git rebase <branch>
的区别:
目标分支超过主分支,并且主分支没有新的提交记录,
*E-*F-*G-*H-*I BRANCH
/
*A-*B-*C-*D MAIN
,fast-forward
和git rebase
合并的效果一样,
*A-*B-*C-*D-*E-*F-*G-*H-*I MAIN | BRANCH
,当主分支有了新的提交(J、K),
*E-*F-*G-*H-*I BRANCH
/
*A-*B-*C-*D-*J-*K MAIN
,就无法使用fast-forward
,合并之后必须有一个单独的合并节点,但是git rebase
仍然可以合并,并且能保持提交线的整洁,
*A-*B-*C-*D-*J-*K-*E'-*F'-*G'-*H'-*I' MAIN | BRANCH
,有冲突的节点因为解决冲突会生成新的commit-id
,有相同提交的记录会被目标分支的节点覆盖,rebase
的节点也不一定是连续的,可能会穿插到主分支已经提交的节点中(按提交先后)。
关于三方合并:
master
|
*C0-*C1-*C2-*C4
\
*C3-*C5
|
iss53
在这样的分支结构中,要把iss53
合并到master
,要使用C4
、C5
和公共祖先C2
,这三个节点做一个三方合并。
三方合并有利于自动合并:例如,节点 C2 有文件 F 包含内容
,节点 C4 的文件 F 包含内容
,节点 C5 的文件 F 包含内容
,现在把iss53
合并至master
,因为三方合并,文件 F 的内容变成了
,因为 C4 在 C2 的基础上清空了第一行,C5 在 C2 的基础上填补了第三行,C2、C4、C5 都有第二行,所以合并的结果是清空第一行、保留第二行和填补第三行,这其中需要公共祖先 C2 的参与。
提示:当合并解决完冲突后,修改提交信息,“添加一些细节给未来检视这个合并的读者一些帮助,告诉他们你是如何解决合并冲突的,以及理由是什么”。