Git源代码管理笔记
很早之前也学过git但是没有详细的记录,这次是做个复习,巩固
若有不对的地方请您指出
Git和SVN有什么区别?
Git | SVN |
---|---|
1. Git是一个分布式的版本控制工具 | 1. SVN 是集中版本控制工具 |
2.它属于第3代版本控制工具 | 2.它属于第2代版本控制工具 |
3.客户端可以在其本地系统上克隆整个存储库 | 3.版本历史记录存储在服务器端存储库中 |
4.即使离线也可以提交 | 4.只允许在线提交 |
5.Push/pull 操作更快 | 5.Push/pull 操作较慢 |
6.工程可以用 commit 自动共享 | 6.没有任何东西自动共享 |
什么是Git?
我建议你先通过了解 git 的架构再来回答这个问题,如下图所示,试着解释一下这个图:
- Git 是分布式版本控制系统(DVCS)。它可以跟踪文件的更改,并允许你恢复到任何特定版本的更改。
- 与 SVN 等其他版本控制系统(VCS)相比,其分布式架构具有许多优势,一个主要优点是它不依赖于中央服务器来存储项目文件的所有版本。
- 每个开发人员都可以“克隆”我在图中用“Local repository”标注的存储库的副本,并且在他的硬盘驱动器上具有项目的完整历史记录,因此当服务器中断时,你需要的所有恢复数据都在你队友的本地 Git 存储库中。
- 还有一个中央云存储库,开发人员可以向其提交更改,并与其他团队成员进行共享,如图所示,所有协作者都在提交更改“远程存储库”。
Git使用 C 语言编写。 GIT 很快,C 语言通过减少运行时的开销来做到这一点。
![clipboard.png](https://images.cnblogs.com/cnblogs_com/FlyingZiming/1695474/o_2004111043192350052359-5ceccb762a5bc_articlex.png)
github仓库
存放项目的地方,一个项目对应一个Repository
public开源,private指定朋友和自己才有权限操作
git网页端的create file可以添加文件,但是太慢了不用
Star和Fork
star就是收藏,下次方便查找
Fork分叉,把别人的项目拿过来,复制一个一样的仓库,独立存在,与clone的区别?
Pull request
fork后的项目你进行了改进,然后发起pull request,等待原项目人查看,决定是否合并
Watch
关注,项目有更新,第一时间收到项目的通知
Issue
事务,发现代码bug,讨论时使用
Issue关闭者可以是提问者也可以是项目拥有者
Commit
每次增删改文件,都提交数据,commit页面可以查看提交信息
工作区域、暂存、仓库
Git Repository 仓库 :最终确定的文件 他人可见
暂存区 :暂存修改的文件统一提交到git仓库总
工作区 :添加、编辑、修改文件的区域
远程仓库:中央服务仓库,多人协作使用
git操作
git status:状态
红色表示未跟踪,可以add到暂存区,绿色表示可以commit到仓库
status把暂存区和工作区进行比较得出未跟踪项、把暂存区和仓库比较得出可以提交的项
git add 文件 :把文件添加到暂存区
git commit -m "提交描述": 暂存区文件提交到仓库
初始化git
用户名邮箱
git config --global user.name 'Aiden-Potter'
git config --global user.name '2834691652@qq.com'
在文件夹内初始化git
git init
生成一个隐藏的 .git文件夹,存储本地仓库的信息
git status
git add first.txt
git commit -m "提交描述"
git log //查看日志
git log --decorate --oneline//一行日志
ls //显示当前目录下的所有文件
cat //看一看当前文件
删除文件
rm -rf first.txt
git rm first.txt
git commit -m '描述'
git reset HEAD 命令恢复暂存区域
git commit -am "change the license file"合并了add和commit两个指令
-a 选项其实是专为懒人添加的。添加了 -a 选项,Git 会自动帮你将工作目录中所有“已跟踪”的文件先 add 到暂存区域,然后再执行 commit 命令。另外,-am 是 -a -m 的缩写,多个选项可以写在一起
管理远程仓库
作用:备份、共享
远程git服务器
git push 本地仓库同步到远程仓库
1、将远程仓库克隆到本地
先复制仓库地址
git clone 仓库地址
设置git config
vi .git/config
不能提交一般是权限不够
2、做你的事情 添加删除文件等等,和上面一样,add然后commit到本地仓库
3、最后git push上去
git pull 和 git fetch 有什么区别?
git pull
命令从中央存储库中提取特定分支的新更改或提交,并更新本地存储库中的目标分支。
git fetch
也用于相同的目的,但它的工作方式略有不同。当你执行 git fetch
时,它会从所需的分支中提取所有新提交,并将其存储在本地存储库中的新分支中。如果要在目标分支中反映这些更改,必须在 git fetch
之后执行git merge
。只有在对目标分支和获取的分支进行合并后才会更新目标分支。为了方便起见,请记住以下等式:
git pull = git fetch + git merge
什么是 git stash?
首先应该解释 git stash 的必要性。
通常情况下,当你一直在处理项目的某一部分时,如果你想要在某个时候切换分支去处理其他事情,事情会处于混乱的状态。问题是,你不想把完成了一半的工作的提交,以便你以后就可以回到当前的工作。解决这个问题的答案是 git stash。
再解释什么是git stash。
stash 会将你的工作目录,即修改后的跟踪文件和暂存的更改保存在一堆未完成的更改中,你可以随时重新应用这些更改。
什么是git stash drop?
通过说明我们使用 git stash drop
的目的来回答这个问题。
git stash drop
命令用于删除隐藏的项目。默认情况下,它将删除最后添加的存储项,如果提供参数的话,它还可以删除特定项。
下面举个例子。
如果要从隐藏项目列表中删除特定的存储项目,可以使用以下命令:
git stash list:它将显示隐藏项目列表,如:
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert “added file_size”
stash@{2}: WIP on master: 21d80a5 added number to log
如果要删除名为 stash@{0} 的项目,请使用命令 git stash drop stash@{0}。
git config 的功能是什么?
首先说明为什么我们需要 git config
。
git 使用你的用户名将提交与身份相关联。 git config
命令可用来更改你的 git 配置,包括你的用户名。
下面用一个例子来解释。
假设你要提供用户名和电子邮件 ID 用来将提交与身份相关联,以便你可以知道是谁进行了特定提交。为此,我将使用:
git config –global user.name "Your Name": 此命令将添加用户名。
git config –global user.email "Your E-mail Address": 此命令将添加电子邮件ID。
什么是 Git 中的“裸存储库”?
你应该说明 “工作目录” 和 “裸存储库” 之间的区别。
Git 中的 “裸” 存储库只包含版本控制信息而没有工作文件(没有工作树),并且它不包含特殊的 .git
子目录。相反,它直接在主目录本身包含 .git
子目录中的所有内容。
而工作目录包括:
- 一个
.git
子目录,其中包含你的仓库所有相关的 Git 修订历史记录。 - 工作树,或签出的项目文件的副本。
搭建个人博客
github.io
有待完善
分支
git branch 分支名
假设创建了一个feature分支
git checkout feature//切换分支
git checkout -b feature2//切换并新建分支
git branch -d 分支名//删除分支
如果试图删除未合并的分支,Git 会提示你“该分支未完全合并,如果你确定要删除,请使用 git branch -D 分支名 命令。
切换分支后:
分支合并
git merge feature//把feature分支合并到当前所处的分支
冲突,无非就是像两个分支中存在同名但内容却不同的文件,Git 不知道你要舍弃哪一个或保留哪一个,所以需要你自己来决定。(大白话:你想合并到master分支,你是从master分支来的,合并的时候你不知道master分支已经有改动了,和你之前的记录不一样,所以就冲突)
合并出现冲突当前工作目录的文件需要进行取舍,Git 会在有冲突的文件中加入一些标记。
一般来说把master分支的东西先pull下来,然后再把自己的merge进去
Git 的分支原理实际上只是通过一个指针记载,所以创建和删除分支都几乎是瞬间完成。
通常情况下,Git 会自动解决一些它能够理解的“冲突”,不需要你来干预;但如果是 SVN 之流则需要你亲自处理每一次合并的冲突。
Fast-forward
所谓的 Fast-forward 就是当待合并的分支位于目标分支的直接上游时,Git 只需把目标分支的指针直接移动即可实现合并。
Three-way merge
如果待合并的两个分支不在同一条线上,那么进行合并就需要解决一个根本的问题 —— 冲突!
对于冲突的处理,Git 相对来说是比较机智的。
举个例子:
合并 C3 和 C4 得到 C5,但 C5 应该如何处理“冲突”呢?
SVN 会把问题抛给用户,让用户自行解决;Git 则显得更为高明,它会找到第三个快照,然后综合三者特点自动解决冲突。
那第三个快照应该如何决定呢?
没错,应该找两者的共同“祖先”作为参照物,一比较就知道两个分支都干了些什么。
图片中 C3 和 C4 的共同祖先是 C1,可以看到 C3 和 C4 分别增加了 test2.py 和 test1.py 两个文件。因为对比之后发现三者并没有冲突,所以 C5 应该是三者的合体,即同时拥有 common.py、test1.py 和 test2.py 三个文件
另外,值得一提的是,Git 这种合并方式也适用于同名文件的不同更改。
举个例子:
这里 C3 和 C4 都只有一个文件(test.txt),但是内容却不一样。如果这样合并,你猜 Git 会不会报“冲突”?
答案是不会的!
因为 Git 找到它们的共同祖先 C1,可以看到 C3 和 C4 都是在 C1 的基础上进行添加(C4 在第 2 行添加了“I”,C3 在第 4 行增加了“FishC”,C1 第 3 行的“love”是它们共同拥有的),同时在每一行并没有产生冲突的地方,所以自动合并后的 C5 是这样的:
- # test.txt
- I
- love
- FishC
注意:如果 Git 检测到同一行有不同的内容,还是会报冲突并让你自行决定谁去谁留的!
Git 工作流程
分支策略?
这个问题被要求用Git来测试你的分支经验,告诉他们你在以前的工作中如何使用分支以及它的用途是什么,你可以参考以下提到的要点:
-
功能分支(Feature branching)
要素分支模型将特定要素的所有更改保留在分支内。当通过自动化测试对功能进行全面测试和验证时,该分支将合并到主服务器中。
-
任务分支(Task branching)
在此模型中,每个任务都在其自己的分支上实现,任务键包含在分支名称中。很容易看出哪个代码实现了哪个任务,只需在分支名称中查找任务键。
-
发布分支(Release branching)
一旦开发分支获得了足够的发布功能,你就可以克隆该分支来形成发布分支。创建该分支将会启动下一个发布周期,所以在此之后不能再添加任何新功能,只有错误修复,文档生成和其他面向发布的任务应该包含在此分支中。一旦准备好发布,该版本将合并到主服务器并标记版本号。此外,它还应该再将自发布以来已经取得的进展合并回开发分支。
最后告诉他们分支策略因团队而异,所以我知道基本的分支操作,如删除、合并、检查分支等。
Git 工作流使用一个中间仓库作为所有开发者的交流地点,开发程序的小伙伴在本地工作,然后将各自的分支推送到中间仓库。
开发分支(develop)
代替单一的 master 主分支,上图的工作流使用了两个分支来处理项目发布和日常开发。
master 主分支通常只是用于对外发布项目的新版本,日常开发应该在另一条分支上完成。我们把开发用的分支叫做 develop 分支。
功能分支(feature)
每一个新功能应该使用单独一个功能分支进行开发,功能分支应该从开发分支中分离出来,功能开发完成后合并到开发分支。
提示1:功能分支不应该跟 master 分支有任何交流。
提示2:功能分支可以采用 feature-* 的形式命名。
预发布分支(release)
在项目正式发布之前,你可能需要一个预发布的版本进行测试。于是你可以从开发分支中分离出预发布分支,用于内部或公开的测试。
提示1:预发布分支应该同时合并到主分支和开发分支中。
提示2:预发布分支可以采用 release-* 的形式命名。
维护分支(hotfix)
项目正式发布后难免会出现 bug,这时就需要创建一个分支,进行 bug 的修补。
提示1:维护分支应该从主分支中分离出来,bug 被修补后,再合并到主分支和开发分支中。
提示2:维护分支可以采用 fixbug-* 的形式命名。
常设分支
常设分支就主分支(master)和开发分支(develop)两个即可,另外的功能分支(feature)、预发布分支(release)和维护分支(hotfix)属于临时分支,用完之后应该及时删除。
So,在正式开发中,Git 的分支管理如下:
冲突处理
pull下来,合并失败然后看哪些地方冲突
git 冲突是怎么产生的
首先,一个用git 写代码,而且只有一个本地分支的情况下是不会又冲突的.
冲突可以说是两个分支的冲突.具体是两个已经提交的分支的相同文件相同位置的的不同操作进行了合并
不会冲突的习惯是,修改文件之前先merge 别的分支.
我在master 分支上创建并提交一个文件,切换到新的b分支上是没有这个文件的.这说明分支之间是相互独立的.
通过git merge master 把master上新增的文件给merge 过来.这是不会又冲突的.0+x = x
如果我在新的分支b上把master 对应行的数据给改了,并提交.然后切换到master,我再git merge b -m 'from b' 也不会冲突,结果是被b分支的修改给覆盖了.
冲突的原因:
如果我切换到分支b ,修改了master 原本那行的代码,提交.然后再切换到master.我不知道b修改了这个文件.我也修改这一行的代码,并提交.好了,"两个分支相同文件相同位置的的不同操作" 我这个时候就在master merge b 或在 b上merge master. 冲突!!! 不解决冲突是没法提交和切换到别的分支的. 反正这个冲突后的文件必须被改动一下.
自动合并:
上面冲突的原因的句子改为,我不知道b修改了这个文件.我[我在我自己的代码上做了修改,b并没有动我代码]的代码,并提交,然后去合并b ,不会冲突,即便我没有先merge b.这种情况是自动合并.
如何解决冲突:
冲突发生的时候,最好能联系一下开发的人员,一起解决冲突.
一般情况下冲突后的文件会是:
<<<<<<<<HEAD
other code
========
your code
\>>>>>>>>your branch name
解决的一般办法是:仔细对比,取综合的并集,就是尽量把所有不同的文件保留,共同的只留一份
个人的一点经验:多人协作开发的时候,如果出现了你没有改过的文件跟你冲突了,一定要去找到当事者,说清楚是如何冲突,然后协商解决,千万不要擅自拉别的分支去试图解决冲突,或找文件覆盖.同时记住,解决了之后,要add 和 commit 最后push.为保证万无一失,最后在冲突都解决之后,重启项目,特别是指服务器项目,保证至少不会有立即奔溃的现象发生.然后才去提交,push.
提交的时候,一定要保持清醒,先搞清楚自己要提交的文件之间的关系,然后再提交,这样才不会有文件缺失的问题,造成奔溃.
如果任务比较多,又建议开多个分支,分别进行开发.还是老话,一定要清楚自己在各个分支上做了什么,自己要提交的是什么.最好是能做个详细的笔记.好记性不如烂笔头.
回滚
git add 命令用于把工作目录的文件放入暂存区域
git commit 命令用于把暂存区域的文件提交到 Git 仓库
git reset 命令用于把 Git 仓库的文件还原到暂存区域
git checkout 命令用于把暂存区域的文件还原到工作目录
git log //查看历史提交
黄色的是计算出来的commit ID,它其实一个完整的 SHA-1 校验和(尽管你的文件内容可能跟我的完全一致,但这个值却不一样,这是因为账号、时间不同而导致),在任何时候都是不一致的
reset默认回滚到暂存区
HEAD 表示最新提交的快照(31f46),而 HEAD~ 表示 HEAD 的上一个快照(d19e3)
执行前
git reset HEAD~ //执行回滚,返回HEAD的前一个快照
执行后
这份快照会弹出到暂存区,此时工作区里的代码还是未回滚之前的,所以git status会提示add
状态如下图:
这里有一点要补充的:HEAD~ 表示 HEAD 的上一个快照(d19e3),HEAD~~(00c29)则表示 HEAD 的上上一个快照,HEAD~10表示第十个快照
--soft
git reset --soft HEAD~ //命令就相当于只移动 HEAD 的指向,但并不会将快照回滚到暂存区域。
事实soft reset就是相当于撤消了上一次的提交(commit)
--hard
git reset --hard HEAD~
//加上 --hard 选项,reset 不仅移动 HEAD 的指向,
//将快照回滚动到暂存区域,它还将暂存区域的文件还原到工作目录。
三个区域保持一致
--mixed
git reset HEAD~ 命令其实是 git reset --mixed HEAD~ 的缩写,默认的到暂存区
回滚指定快照
如果快照比较多,你又懒得去数有多少个“~”,那么你可以通过指定具体的快照 ID 来回滚该快照。
比如 git reset 00c2929
一般只要输入前几位(5 位或以上)就可以了
回滚个别文件
reset 不仅可以回滚指定快照,还可以回滚个别文件。
命令格式为 git reset 快照 文件名/路径
这样,它就会将忽略移动 HEAD 的指向这一步(因为你只是回滚快照的部分内容,并不是整个快照,所以 HEAD 的指向不应该发生改变),直接将指定快照的指定文件回滚到暂存区域
前滚
知到快照ID的情况西可以使用前滚,但是git log无法给出之前的快照ID
这个时候应该
git reflog //可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作)
我们就可以买后悔药,恢复到被删除的那个版本。
版本比较
git diff //比较暂存区域与工作目录的文件内容
diff 命令是 linux 上非常重要的工具,用于比较文件的内容,特别是比较两个版本不同的文件以找到改动的地方。diff 程序的输出被称为补丁 (patch),因为 Linux 系统中还有一个 patch 程序,可以根据 diff 的输出将 a.c 的文件内容更新为 b.c。
diff很好的支持了二进制文件
第一行:diff --git a/change.txt b/change.txt
表示对比的是存放在暂存区域的 change.txt 和工作目录的 change.txt
第二行:index f3984d0..fa7616e 100644
表示对应文件的 ID 分别是 f3984d0和 fa7616e ,左边暂存区域,后边当前目录。
最后的 100644 是指定文件的类型和权限,下面的表就是linux系统的定义
The following flags are defined for the st_mode field:
S_IFMT 0170000 bit mask for the file type bit fields
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
S_ISUID 0004000 set UID bit
S_ISGID 0002000 set-group-ID bit (see below)
S_ISVTX 0001000 sticky bit (see below)
S_IRWXU 00700 mask for file owner permissions
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 mask for group permissions
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 mask for permissions for others (not in group)
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission
---change.txt 表示旧文件
+++change.txt 表示新文件
@@ -1 +1,2 @@
以 @@ 开头和结束,中间的“-”表示旧文件,“+”表示新文件,后边的数字表示“开始行号,显示行数”
那为啥 -1 后边没有显示的行数?
因为在合并显示的结果中,旧文件已经完全包含在新文件中了(也就是旧文件没有自己“独有的”内容)。
最后空一行是一个良好的编程习惯
文件较多就需要翻页
j
k
f
b
四个快捷键;g
跳转,g3
跳转到第三行;?
或者/
+ 搜索内容 = 匹配的关键字高亮显示
q退出;h进入帮助命令;
指定快照比较
给出两个快照ID就可以
git diff 6e26975 ed3708c
git diff HEAD //比较最新提交的快照和当前目录的内容
git diff --cached //比较最新提交的快照和暂存区域的文件
![](https://images.cnblogs.com/cnblogs_com/FlyingZiming/1695474/o_200411104132160404xyr6s8w33y30w6y6.png)
在 Windows 下,如果你看到乱码,乃是由于 Windows 的不团结导致编码问题,请使用全世界通用的 UTF-8 无 BOM 格式。
使用 Nodepad++ 打开文件,点击“格式(M)”->“转为 UTF-8 无 BOM 编码格式”。
修改提交
Situation One:版本刚一提交(commit)到仓库,突然想起漏掉两个文件还没有添加(add)。就好比你是老司机,说开车就开车,到了半路发现还有俩乘客没上来……
Situation Two:版本刚一提交(commit)到仓库,突然想起版本说明写得不够全面,无法彰显你本次修改的重大意义……
无需回滚,一步到位
git commit --amend
改上面这一行黄色的可以改描述,i
插入,shift
+z
+z
保存退出
或者可以按下冒号:
,然后输入 q!
退出。那么会 Git 会保留旧的提交说明。
删除和重命名
删除
git rm yellow.jpg //把刚刚的黄图删了
但此时git仍会追踪变化,因为已经commit了,暂存区和仓库的比较是这个被删了
应该还有一步
git reset --soft HEAD~//快照回滚到上一个位置
接着重新提交就好了
rm 命令删除的只是工作目录和暂存区域的文件(即取消跟踪,在下次提交时不纳入版本管理)
git rm readme.txt --cached//仅删除暂存区的东西
rm .git/index//完全清空暂存区
重命名
如果自己直接改,他会检测两个文件
![img](https://images.cnblogs.com/cnblogs_com/FlyingZiming/1695474/o_200411104224224707mw08vn1zhntyuw99.png)
git mv game.py wordgame.py //让git帮你改名
其相当于
ren game.py wordgame.py
git rm game.py
git add wordgame.py
gitignore
可以忽略某些文件的变化
echo .gitignore
然后就编辑它
.gitignore 语法规范
.gitignore 可以使用标准的 glob 模式匹配(glob 模式是指 shell 所使用的简化了的正则表达式):
- 所有空行或者以注释符号 # 开头的行都会被 Git 忽略;
- 星号(*)匹配零个或多个任意字符;
- [abc] 匹配任何一个列在方括号中的字符;
- 问号(?)只匹配一个任意字符;
- [a-z] 匹配所有在这两个字符范围内的字符;
- 匹配模式最后跟反斜杠(/)说明要忽略的是目录;
- 匹配模式以反斜杠(/)开头说明防止递归;
- 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
一般找模板就行了