git clone
网址 [本地文件夹名]git init
git status
git diff [file]
git log
[-number] [分支名]git reflog
git blame
git cat-file -[t|s|p] 哈希值
git config
git add ./文件名/文件夹名
git rm
git mv [file] [newFile]
git restore
git remote
git fetch [alias]
git pull
[<远程主机名> <远程分支名>:<本地分支名>]git push <远程主机名> <本地分支名>:<远程分支名>
git branch
[branchName]git checkout
[分支名]git merge
git commit
-m “message”git reset
[–soft | --mixed | --hard] [HEAD] [-- file]git rebase
git stash
git rerere
.git
文件夹下的文件.gitignore
文件里指定不需要 Git 管理的文件git push -f
git clone
网址 [本地文件夹名]克隆 Git 仓库到本地
--bare
: 新建一个裸仓库,不将代码放到中,而是将
/.git 本身设置为仓库,无法签出工作树,此外,远程的分支头直接复制到相应的本地分支头,而不将它们映射到
refs/remotes/origin/
。使用此选项时,既不会创建远程跟踪分支,也不会创建相关的配置变量。
git init
创建 Git 仓库
把已有的项目代码纳入 Git 管理
cd
项目代码所在的文件夹
git init
新建的项目直接用 Git 管理
cd
文件夹
git init 项目文件名
’
注: 会在当前路径下创建和项目名称同名的文件夹
git status
查看仓库当前的状态,显示有变更的文件。
-s
: 简短的输出git diff [file]
显示暂存区与工作区的差异
例:
git diff HEAD
显示工作区和暂存区与最后一次 commit 之间的差异
[--cached|--staged] [file]
: 显示暂存区和最后一次提交(commit)的差异
[first-branch]...[second-branch] [-- file]
: 显示两次提交或两个分支之间的差异,如果最后有–文件名,就是对比两次提交指定文件的差异
例 1:
git diff 003e2f133adc5a53f21a72ca5b62eb08566121d1
> 例 2:git diff 003e2f133adc5a53f21a72ca5b62eb08566121d1...e77f6c3cc85fd535c36df30813ed23e9fb8255d3
> 例 3:git diff temp master --Git.md
git log
[-number] [分支名]查看历史提交记录
例:
git log -2
// 查看最近的两次提交记录
--oneline
查看简要历史记录--graph
查看图形化的日志--reverse
逆向显示日志--author
查找指定用户的提交日志git reflog
查看本地所有分支的所有操作记录,(包括已经被删除的 commit 和 reset 的操作)
delete
: 删除指定的记录例:
git reflog delete HEAD@{270}
git blame
以列表形式
查看指定文件的修改记录
git cat-file -[t|s|p] 哈希值
查看Git对象
的属性
t
: 查看 git 对象的类型s
: 查看 git 对象的大小p
查看 git 对象的内容例: git cat-file -p 003e2f133adc5a53f21a72ca5b62eb08566121d1
git config
查看、设置或清除配置
[--local|--global|--system] [config 'message']
: 设置配置例:
git config [–local|–global|–system] user.name ‘You name’
git config [–local|–global|–system] user.email ‘You email’
git config --list [--local|--global|--system]
: 查看配置例:
git config --list --local
git config --unset [--local|--global|--system]
: 清除配置例: git config --unset --local user.name
区别: local: 当前仓库 global: 当前用户的所有仓库 system: 本系统的所有用户
优先级: local > global > system
git add ./文件名/文件夹名
将文件添加到暂存区,. 表示所有文件
-u
: 仅添加已被跟踪的文件git rm
将文件从暂存区和工作区中删除
例:
git rm hello.txt
-f
: 强制删除选项,用于删除之前修改过并且已经放到暂存区域(必须)例:
git rm -f hello.txt
--cached
把文件从暂存区域移除,但仍然保留在当前工作目录中,换句话说,仅是从跟踪清单中删除例:
git rm --cached hello.txt
-r
递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件例:
git rm –r *
#删除当前目录下的所有文件和子目录
git mv [file] [newFile]
用于移动或重命名一个文件、目录或软连接
-f
: 重命名例:
git mv -f hello.txt hello.css
git restore
把未 add 到暂存区的文件修改撤销
例 : git restore public_knowledge\Git\Git.md
--staged
: 把文件从暂存区撤回到工作区,保留文件最后一次修改的内容
-s SHA file
: 表示将当前工作区或文件切换到指定 commit 版本
例 : git restore -s 703025cf public_knowledge\Git\Git.md
git remote
用于在远程仓库的操作
-v
: 显示所有远程仓库例:
git remote -v
show [remote]
: 显示某个远程仓库的信息例:
git remote show https://github.com/1758231591/Learning-notes-and-materials.git
remove name
: 删除远程仓库
rename old_name new_name
: 修改仓库名
add
: :在本地仓库添加一个远程仓库
git fetch [alias]
用于从远程获取代码库
例:
git fetch origin
取回更新后,会返回一个 FETCH_HEAD
,指的是某个 branch 在远程仓库上的最新状态,可以在本地通过它查看刚取回的更新信息,可以看到返回的信息包括更新的文件名,更新的作者和时间,以及更新的代码。
通过这些信息来判断是否产生冲突,以确定是否将更新 merge 到当前分支。
git log -p FETCH_HEAD
git pull
[<远程主机名> <远程分支名>:<本地分支名>]从远程获取代码并合并本地的版本,其实就是 git fetch
和 git merge FETCH_HEAD
的简写
例 1:
git pull origin master
// 如果远程分支是与当前分支合并,则冒号后面的部分可以省略
例 2:git pull origin master:main
// 将远程主机 origin 的 master 分支拉取过来,与本地的 main 分支合并
--rebase
: push 失败,需要先把服务器上的代码给 pull 下来,为了避免有 merge 动作,可以使用
相当于 git fetch + git rebase FETCH_HEAD
git push <远程主机名> <本地分支名>:<远程分支名>
用于从将本地的分支版本上传到远程并合并
例:
git push origin master
相当于git push origin master:master
-f
: 本地版本与远程版本有差异时,可以使用这个参数强制推送,多人合作禁用,如果要用可以使用 git push --force-with-lease
,相对安全-d
: 删除远程主机的分支--all
: 推送全部分支-u
: 如果当前分支与多个主机存在追踪关系,则可以使用 -u
参数指定一个默认主机,这样后面就可以不加任何参数使用 git push,不带任何参数的 git push,默认只推送当前分支。如果想更改设置,可以使用 git config 命令。git config --global push.default matching
或 git config --global push.default simple
ssh
协议推送: gitHub: git push [email protected]:DuSenYao/Learning-notes-and-materials.git
注: 需要 配置公私钥
git branch
[branchName]不加 name 是列出本地分支,加 name 是创建分支
-r
: 查看远程分支例:
git branch -r
-a
: 查看所有分支-d/D
: 删除分支,-D 是强制删除-v
: 查看分支版本git checkout
[分支名]切换分支
-b
: 创建并直接切换到新分支例:
git checkout -b test
-- [file]
: 将工作区文件恢复为和暂存区一样例:
git checkout -- index.html
-b name origin/branchName
: 基于远程的分支创建一个本地的分支,并切换到新分支例:
git checkout -b dev origin/dev
git merge
合并分支
例:
git merge dev
[alias]/[brach]
: 将远程的分支合并到当前分支例:
git merge origin/master
--allow-unrelated-histories
: 用于合并后两个没有共同祖先的历史记录
--continue
: 合并由于冲突停止后,可以使用这个参数继续合并
git commit
-m “message”主要是将暂存区里的改动给提交到本地的版本库,message 填写摘要
-a
: 跳过暂存区,从工作区直接提交到本地版本库--amend
: 追加提交,在不增加一个新的commit
的情况下,将新修改的代码追加到前一次
的 commit 中git reset
[–soft | --mixed | --hard] [HEAD] [-- file]用于回退版本,可以指定暂存区退回某一次提交的版本
--mixed
: 默认参数,可以不用带该参数,清空暂存区,工作区文件内容保持不变。例1: git reset HEAD^ // 回退所有内容到上一个版本
例2: git reset HEAD^ hello.css // 回退 hello.css 文件的版本到上一个版本
例3: git reset 052e // 回退到指定版本
--soft
: 保留工作区的更改内容,并把重置版本带来的差异放入暂存区例:
git reset --soft HEAD
回退到当前版本
--hard
: 将指定版本的内容放入暂存区和工作区,也就是所有没有 commit 的修改都会丢失,慎用!例1: git reset –hard HEAD~3 // 回退上上上一个版本
例2: git reset –hard bae128 // 回退到某个版本回退点之前的所有信息。
例3: git reset --hard origin/master // 将本地的状态回退到和远程的某个分支一样
edition -- file
: 取消部分文件的更改例:
git reset HEAD -- index.html
git rebase
合并提交记录
使用场景:
本地开发分支灵活管理
· 在自己本地 git checkout -b local 创建一个本地开发分支
· 在本地的开发分支上开发和测试
· 阶段性开发完成后(包含功能代码和单元测试),可以准备提交代码
· 首先切换到master分支,git pull拉取最新的分支状态
· 然后切回local分支
· 通过 git rebase local -i 将本地的多次提交合并为一个,以简化提交历史。本地有多个提交时,如果不进行这一步,在git rebase master时会多次解决冲突(最坏情况下,每一个提交都会相应解决一个冲突)
· git rebase master 将master最新的分支同步到本地,这个过程可能需要手动解决冲突(如果进行了上一步的话,只用解决一次冲突)
· 然后切换到master分支,git merge local 将本地的 local 分支内容合并到 master 分支
· git push将master分支的提交上传
-i
: 打开 vim 编辑模式,执行会自动打开 vim 编辑模式,合并的记录前面都有相同的指令 pick,下面有 commands,根据这些指令可以修改,修改后 ESC -> :wq!
保存并退出,就会进入注释界面,编辑好后退出即可。使用各种指令可以完成各种 commit 提交记录的合并
--continue
: 合并冲突,结合 “git add 文件” 命令一起用与修复冲突,提示开发者,一步一步地有没有解决冲突。
--abort
: 放弃合并,回到 rebase 操作之前的状态,之前的提交的不会丢弃
--skip
: 则会将引起冲突的 commits 丢弃掉(慎用);
打开 git 自带的图形界面工具
git stash
临时保存和恢复修改,可跨分支,在 未add
之前才能执行
[save message]
: 保存修改到临时目录,并把工作区的文件还原到上一次 commitlist
: 显示所有保存的记录列表pop stash@{num}
: 恢复,num 是可选值,通过 git stash list
查看具体值,只能恢复一次apply stash@{num}
: 恢复,num 是可选值,通过 git stash list
查看具体值,可恢复多次例:
git stash apply stash@{0}
drop stash@{num}
: 删除指定保存clear
: 删除所有保存git rerere
重用记录的解决方案,它允许 Git 记住解决一个块冲突的方法,这样在下一次看到 相同的冲突 时,Git 可以自动地解决它。
rerere
启用 :git config --global rerere.enabled true
实际应用不常用,查看 Git 文档
.git
文件夹下的文件HEAD
: 指向当前所在的分支
config
: 当前 git 的配置文件,这是个引用指向 refs 文件夹 下的 heads 文件夹 里的分支
refs文件夹
:
objects文件夹
: 存放所有的git对象
,对象哈希值前 2
位作为文件夹名称,后 38
位作为对象文件名, 可通过 git cat-file -p
命令,拼接文件夹名称+文件名查看
commit
是一个提交,它里面有一个tree
对象对应唯一的tree
,这个 tree 里面又有包含了 多个 tree 和 blob 对象 ,每个 tree 对象又包含了多个 tree 和 blob,文件的的最终形式是 blob。对于 blob,git 会认为文件内容相同时,就使用同一个 blob,这样就极大的避免了频繁提交时,git 的存储空间大幅上升。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KdLbh5YY-1616291917812)(./image/git中commit、tree和blob三个对象的关系.png)]
添加或者修改了文件并且add
到Stage Area
之后,首先会根据文件内容创建不同的blob
,当进行提交之后马上创建一个 tree 组件把需要的 blob 组件添加进去,之后再封装到一个 commit 组件中完成本次提交。
在将来进行 reset 的时候可以直接使用 git reset --hard xxxxx
可以恢复到某个特定的版本,在 reset 之后,git 会根据这个 commit 组件的 id 快速的找到 tree 组件,然后根据 tree 找到 blob 组件,之后对仓库进行还原,整个过程都是以 hash 和二进制进行操作,所以 git 执行效率非常之高。
没有文件也就是没有 blob 对象的目录是不会被 git 管理的,因为 git 是对文件进行版本管理,所以没有必要对空目录生成对象。
分离头指针
是指在没有任何分支的情况下做 commit。
优缺点 : 用于实验性的更改与提交,随时可以放弃,而不影响任何分支的状态。缺点也是没有分支,意味着一旦切换分支,这些 commit 都会被当做垃圾丢弃。
HEAD
在 brach 时,指代最新的commit
,而在分离头状态时指代具体的 commit。
含义与用法 :
例 :
HEAD~2^2
// 最新 commit 的父节点的父节点的第二个父节点
.gitignore
文件里指定不需要 Git 管理的文件例 : .gitignore
path/to/repo.git
file://path/to/repo.git
http://git-server.com/path/to/repo.git
[email protected]:path/to/repo.git
是工作中最常用的智能协议哑协议与与智能协议的区别:
1.哑协议传输进度不可见,智能协议传输可见 2.智能协议比哑协议传输速度快
git config --global core.editor "code -w"
git push -f
强制推送,即使不是 fast-forward
1
比如: 公共分支
pull
到本地做变基
操作,会导致历史消失。
在本地创建 SSH
秘钥
在本地使用
ssh-keygen -t ed25519 -C "[email protected]"
在C:\Users\用户名\.ssh\id_rsa.pub
文件里,就有创建出来的公钥
,把公钥复制出来,粘贴到 GitHub 上。
ssh 协议需要这个,使用 ssh 传输协议,不需要账户密码就可以连接 gitHub。
在搜索页,语言栏左下方有高级搜索(Advanced search)
组织里可以管理多个仓库,加成员,设置团队,设置团队成员管理权限。
成员可以看见每个团队管理的仓库和权限,可以发起请求加入团队。
可以在 Wiki 中添加指导文档。能够添加 首页、工具栏 和 各种指导文档页面。文档使用 markdown 格式。
s
先在 GitHub 上,创建团队类型的仓库。需要基于一个组织创建。
需要考虑的因素 :
主干开发适用于 :
Git Flow 适用于 :
GitHub FLow 适用于 :
GitLab Flow (带生产分支) 适用于:
GitLab FLow (带环境分支) 适用于:
GitLab Flow (带发布分支) 适用于:
位置: 仓库 -> Settings -> options -> Merge button
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lEATxsni-1616291917831)(./image/Merge_button.png)]
Projects 可以有序的管理 issue 和 Pull request
在 issue 和 Pull request 中可以选择分到哪个 project 中,项目可以设置自动化管理。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CUpAo5pR-1616291917833)(./image/Projects.png)]
位置: 仓库 -> Settings -> Branches -> Branch protection rules 中可以添加分支保护规则
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BzlTYEhe-1616291917835)(./image/Branch-protection-rule.png)]
有两种方法:
git push
之前发现远程又有了更新,可以将本地的提交回退掉,避免掉无用的远程 merge 本地分支的提交记录,使用如下命令:
git reset HEAD~
>git pull
然后重新进行新的提交,这样就可以避免远程与本地分支的 merge
提交记录,让 git 的提交历史更加干净。
rebase
,在本地解决掉冲突并完成自测。使用 git merge
远程分支名 合并分支,然后 git push
。
使用 git pull
,然后手动解决冲突(与另一个提交者交流后)
分两种情况:
没有修改相同位置,没有修改的冲突,变更文件名和变更文件内容的操作能够自动被 git 处理。
如果一个人既变更了文件名又修改了文件,同时另一个人也修改了该文件的同一位置的内容,就会被 git 识别为冲突,而不能自动进行处理了。
原因: git 存放 blob 文件时是以
文件内容
来区分的,并不以文件名来区分。
git pull
到本地分支,git 会保留两个文件,手动来处理冲突,可以用 git rm
删除不要的文件,最后提交。
git rm --cached name_of_file
的方式删除掉 git 仓库里面无需跟踪的文件。GitLab
统一在 issues 下
Git 是可以像 SVN 这样的中心工作流一样工作的。
如果在第 3 步发现 push 失败,因为别人已经提交了,那么需要先把服务器上的代码给 pull 下来,为了避免有 merge 动作,可以使用 git pull --rebase
。这样就可以把服务器上的提交直接合并到代码中,对此,Git 的操作是这样的。
如下图所示。Git 会把 Origin/Master 的远程分支下载下来(紫色的),然后把本地的 Master 分支上的改动一个一个地提交上去(蓝色的)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mjI1hbbo-1616291917836)(./image/git-pull–rebase工作流程.png)]
如果有冲突,那么要先解决冲突,然后做 git rebase --continue
。如下图所示,git 在做 pull --rebase 时,会一个一个地应用(apply)本地提交的代码,如果有冲突就会停下来,等待解决冲突。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dj9E3Ct8-1616291917838)(./image/git-pull–rebase应用代码.png)]
问题
小团队或是小项目可以这么干,但是对比较大的项目或是人比较多的团队,这么干就会有很多问题。
最大的问题就是代码可能干扰太严重。
需要同时开发一个功能的开发人员可以分享各自的代码,但是不会把代码分享给开发其他功能的开发人员,直到整个功能开发完毕后,才会分享给其他的开发人员(也就是进入主干分支)。因此,引入了 “功能分支”。
协同工作流的开发过程如下:
git checkout -b new-feature
创建并切换到 "new-feature"分支。git push -u origin new-feature
把分支代码 push 到服务器上。git pull --rebase
来拿到最新的这个分支的代码。最后通过 Pull Request 的方式做完 Code Review 后合并到 Master 分支上。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2brcqf2a-1616291917838)(./image/功能分支协同工作流.png)]
就像上面这个图显示的一样,紫色的分支就是功能分支,合并后就会像上面这个样子。
这种开发是以服务器为中心的开发,还不是 Git 分布式开发,它只不过是用分支来完成代码改动的隔离。
为什么会叫"功能分支",而不是"项目分支"?因为 Git 的最佳实践希望在开发的过程中,快速提交,快速合并,快速完成。这样可以少很多冲突的事,所以叫功能分支。
传统的项目分支开得太久,时间越长就越合不回去。这种玩法其实就是把一个大项目切分成若干个小项目来执行(最好是一个小功能一个项目)。这样才是互联网式的快速迭代式的开发流程。
生产过程是比较复杂的,软件生产中会有各式各样的问题,并要面对不同的环境。要在不停地开发新代码的同时,维护线上的代码,于是,就有了下面这些需求。
面对这些需求,不仅是要在整个团队中共享代码,要的更是管理好不同环境下的代码不互相干扰。要管理好代码与环境的一致性。
GitFlow 协同工作流是由 Vincent Driessen 于 2010 年在 A successful Git branching model 这篇文章介绍给世人的。
这个协同工作流的核心思想如下图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C5SMCOEa-1616291917839)(./image/GitFlow协同工作流核心思想.png)]
整个代码库中一共有五种分支:
Master 分支 : 也就是主干分支,用作发布环境,上面的每一次提交都是可以发布的。
Feature 分支 : 也就是功能分支,用于开发功能,其对应的是开发环境。
Developer 分支 : 是开发分支,一旦功能开发完成,就向 Developer 分支合并,合并完成后,删除功能分支。这个分支对应的是集成测试环境。
Release 分支 : 当 Developer 分支测试达到可以发布状态时,开出一个 Release 分支来,然后做发布前的准备工作。这个分支对应的是预发环境。之所以需要这个 Release 分支,是因为开发需要继续向前,不会因为要发布而被 block 住而不能提交。
一旦 Release 分支上的代码达到可以上线的状态,那么需要把 Release 分支向 Master 分支和 Developer 分支同时合并,以保证代码的一致性。然后再把 Release 分支删除掉。
Hotfix 分支。是用于处理生产线上代码的 Bug-fix,每个线上代码的 Bug-fix 都需要开一个 Hotfix 分支,完成后,向 Developer 分支和 Master 分支上合并。合并完成后,删除 Hotfix 分支。
这就是整个 GitFlow 协同工作流的工作过程。可以看到:
GitFlow 的问题:
git merge --no-ff
来合并分支,在 git-flow 这样多个分支的环境下会让分支管理的 log 变得很难看。GitHub 的工作流程:
如果有"官方库"的权限,那么就可以直接在"官方库"中建功能分支开发,然后提交 pull request。通过 Code Review 后,合并进 Master 分支,而 Master 一旦有代码被合并就可以马上 release。
这需要一个自动化的 CI/CD 工具做辅助。是的,CI/CD 应该是开发中的标配了。
GitHub Flow 这种玩法依然会有好多问题,因为其虽然变得很简单,但是没有把代码和运行环境给联系在一起。
所以,GitLab 提出了几个优化点。其中一个是引入环境分支,如下图所示,其包含了预发布(Pre-Production)和生产(Production)分支。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GUMUqCX0-1616291917840)(./image/GitLab.png)]
而有些时候,还会有不同版本的发布,所以,还需要有各种 release 的分支。如下图所示。Master 分支是一个 roadmap 分支,然后,一旦稳定了就建稳定版的分支,如 2.3.stable 分支和 2.4.stable 分支,其中可以 cherry-pick master 分支上的一些改动过去。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UZaEYcAi-1616291917840)(./image/GitLab不同版本发布.png)]
这样解决了两个问题:
软件开发的趋势:
以微服务或是 SOA 为架构的方式
一个大型软件会被拆分成若干个服务,那么,代码应该也会跟着服务拆解成若干个代码仓库。这样一来,每个代码仓库都会变小,于是协同工作流程就会变简单。
对于每个服务的代码仓库,开发和迭代速度也会变得很快,开发团队也会跟服务一样被拆分成多个小团队。
这样一来, GitFlow 这种协同工作流程就非常重了,而 GitHub 这种方式或是功能分支这种方式会更适合开发。
以 DevOps 为主的开发流程
DevOps 关注于 CI/CD,需要有自动化的集成测试和持续部署的工具。这样一来,代码发布速度就会大大加快,每一次提交都能很快地被完整地集成测试,并很快地发布到生产线上。
协同工作流的本质,并不是怎么玩好代码仓库的分支策略,而是玩好软件架构和软件开发流程。
与其花时间在 Git 协同工作流上,还不如把时间花在调整软件架构和自动化软件生产和运维流程上来,这才是真正简化协同工作流程的根本。
当前分支合并到另一分支时,如果没有分歧,就会直接移动文件指针。这个过程叫做fast-forward
。fast-forward 能够保证不会强制覆盖别人的代码,确保了多人协同开发。尽量不要使用 non fast forward 方法提交代码。 ↩︎