git的复习和总结

因为过几天就要去适应新的职位了,虽然之前也用过git做版本控制管理,但都是基于自娱自乐的形式,所以都是需要用到什么功能就现查,然后在自己复制粘贴,够用即可,但是新的工作环境毕竟是团队协作,少不了使用更多的git的功能,而且使用不熟悉也是打脸的操作,毕竟现在用git工作就和办公你需要用word一样的普遍,所以现在开始比较全面集中的快速学习并记录一下git的使用,从安装到熟练这样的学习曲线安排起来,以备不时之需。

1.git的安装

https://git-scm.com/book/zh/v2

上面的官网提供了非常详细的各个操作系统下的安装方式,不再赘述,仅以mac操作系统为例,简述为:

1.下载dmg安装包,官网下载即可。

2.打开安装包,根据提示安装。

3.打开命令行,检查git是否安装成功:

git --version 

如果成功,将能看到对应的git版本


git的复习和总结_第1张图片

4.git 更新,如果是很久之前安装的,可以尝试下载更新的安装包,重新安装;又或者你本来是在不同的管理包工具brew等上面安装的git(brew install git),此时仅仅需要用brew对应的升级命令更新包即可:

brew upgrade git


git的复习和总结_第2张图片

5.安装好了git后需要设置你的username,和email地址,这里设置用户名和邮件地址是为了方便管理,因为git这个版本管理软件需要获取你的姓名和email,用以标记后续你创建的资源作出的改动,以及你参与的资源管理有了改动后通过邮件给你发信息通知你。如果你不设置,后续你使用git提交你的文件的时候,也会给你提示,让你设置这些信息:

git config --global user.name 'yourname'

git config --global user.email 'youremail'

config配置有三个作用域值:global就是你名下所有的资源库都生效;

local:是指你在git上创建的某一个资源库下面有效;

system:是凡是你用当前的登陆系统登陆的所有用户都有效果(这是很不常用的);


6.配置前也能使用命令查看当前做了哪些配置:

git --config --list --global 

上面的命令用于查看config list下的global字段配置情况,类似的查看system就把关键字改成global,查看local就改成local,查看全部就只用list;


git的复习和总结_第3张图片

但是查看local的命令,有所不同,因为local是你的名下具体的某一个资源库的信息,所以如果你没有进入到具体的资源库文件下使用这个命令,就会提示你进入到具体的资源文件夹下查看:

创建git Repository

创建你的git资源库,安装完git这个开源的文件版本管理软件后,我们直接上手如何使用它。

试想我们使用git管理你的项目代码或者文件吧,我还是说文件不说项目代码,因为git本质上只是一个工具,不一定是要IT的各种项目,开发代码才能用,虽然用的最多的确实是我们的项目开发,测试,运维团队,但是你比如是一个作家,能不能用git,当然能,我今天写了一些篇章,我改了一些东西,我提交到git上面去,这样我不用去管我现在改动和之前究竟有多大的区别,我git上都有记录,随时回去看某个时间段提交的版本即可,多方便对不对,只要你有文件的版本管理需求就都可以使用这个工具。

来我们接着试想使用git管理你的文件的场景,你会发现大致有两个场景,第一个是你已经有一个文件了,想把它放到git上去进行版本管理,第二个是我啥也没有呢,我就想新建一个git文件,然后在这个文件下面进行我的创作管理;

第一种情况只需要你进入到你的文件目录下执行以下命令对当前文件路径下的所有文件进行初始化,纳入git管理:

cd filename

git init

这样你就在当前已有的文件纳入了git管理,你还会发现提示文件下有一隐藏的.git文件:


git的复习和总结_第4张图片

第二种就是直接用git命令初始化并新建一个git文件夹:

cd filename

git init myfirstgitfile

你会发现这个命令就直接新建一个文件夹并且初始化了:

git的复习和总结_第5张图片

现在我这里有两个文件路径都纳入了git管理,那么我们来试试设置local的环境变量,并检验local环境变量是否生效了;

我们可以在existfile下面执行设置命令把用户名和email都改一下,记得local是当前的资源库的配置信息:


git的复习和总结_第6张图片

git文件提交

现在我们随便在目录下面新建一个文件readme,(因为每个文件下基本都有一个readme,就像国际惯例一样,这个文件提供一些基本信息):

然后我们要把这个新建的readme文件提交到git下面去,git commit -m 'some comments to mark why you commit this file' 

那么我们会发现此时有一行报错信息给你反馈回来了,添加失败,因为下面的几个文件都处于untracked状态;

这是为什么呢,原因是因为,无论我们什么时候使用git,我们都需要现初始化这个资源库(git init/git init filename),并且把这个资源库下面需要被管理或者跟踪的文档文件添加到git里面去,这样我们才能继续在该资源库下面对该文件的进行新增,更新,删除等等跟踪管理操作;


git的复习和总结_第7张图片

git资源库下的文件的跟踪添加:git add readme

此时你可以继续使用git status命令查看当前资源库下面的文件跟踪状态,我们注意到资源库下面本来有三个文件,刚刚添加了一个到git上跟踪,

还有两个是没有做add操作的,所以你会看到它的提示是刚刚添加的readme已经到了cached了,缓存起来了,但是还没有commits,而另外两个文件是untracked状态的;

git的复习和总结_第8张图片

git 添加后,我们提交readme;

git commit -m 'add readme file to git for tracking'

那么我们可以看到我们的readme文件就被提交到git上面去了;

并且我们另外的两个文件因为并没有现对他们做添加到git的缓存里去的操作,我们执行commit的时候就不会添加上去;

git的复习和总结_第9张图片

查看日志

git log; 我们执行命令查看刚刚做的那个操作,可以看到,我们这个readme是提交到了master分支里去的;而且操作者的信息都是local设置的信息,也就是说local的配置是优先级是高于global的;

git的复习和总结_第10张图片

git的目录分析:从刚刚的练习上我们插播一句git工作目录分析,

首先本地工作目录,就是你当前本地的文件夹,初始化后的git init这个目录;然后呢我们用 git add readme 命令给这个文件提交到了git的一个中间目录,缓存目录里;这个缓存目录为啥要设计这样一步呢,原因是通过add命令来到的缓存目录是一个中间目录,里面的文件可以被撤回,就是给用户一个思考时间,你不想提交的东西还能撤回去,不用立马提交到git上去进行版本管理;那么最终通过git commit -m 'comments'提交过去的目录就是git的版本管理目录;


git的复习和总结_第11张图片
图片取自网络

更新提交到git上到文件

现在我们来做一个小练习,刚刚提交到git上到readme,我们打开它添加一点新的东西进去

git的复习和总结_第12张图片

我们保存退出,再次查看状态,git status: 可以看到的是git当前的工作目录下的状态出现了改变,它会记录你当前工作目录下面做了哪些改变,会提示你修改了readme文件,但是你还没有commit到git上去,它提示你用add添加到缓存,或者使用checkout命令删除刚刚做的改动;


git的复习和总结_第13张图片

现在我们使用 git add readme 或者git add -u(-u适用于当前目录下有多个已经提交到git上被跟踪到文件同时被修改了,一键add更新)。那么我们也会发现你add后,他会提示你可以进一步commit到git上,也可以通过git reset HEAD filename去倒退回工作区,也就是还没有执行add的那个状态:这里你也能更加清晰的看到,这个缓存区的中间状态,你可以修改文档,add到中间缓存区,然后提交到git上去,也可以在中间缓存区通过reset 退回到没有add之前的状态;


git的复习和总结_第14张图片


那么我们还是add,commit一下,然后看看log,你可以清楚的看到,我们总共就做了两次commit,第一次是新建后commit,第二次是updating:

其实如果使用过其他的版本管理工具的朋友理解这些提交,变迁,记录,会很好理解,因为本质上版本管理工具就是给你的文件打上标签,对你的文件每一个操作都进行记录或者跟踪,如果是从来没有用过管理工具的朋友就尝试多这样一步步练习,新建,添加,查看状态,提交,查看状态,查看日志,多练习几遍就很快能理解git的工作模式了。

git的复习和总结_第15张图片

修改文件名的小技巧

那么我们刚刚学会了修改文件,更新文件如何添加到缓存,再提交到git上去,如果我们仅仅是修改了一个文件的名称,那么可以使用一个简便的命令:使用 git mv fileorigin newfilename

这样的修改命令的方式,可以省去再重新add到缓存这一步,它默认就直接add到缓存了,你只需要执行commit就能添加到git上去了:


git的复习和总结_第16张图片

更多查看log的命令

前面我们用到了 git log查看日志

我们还可以用 git log -/n1/n2/n3/n4 来查看最近一,二,三,四次的修改记录,git log -n1 --oneline 可以用来查看最近一次修改日志的记录并且仅仅返回日志的第一句话,这样我们看的更加省力,有时候不需要看那么多的记录;


git的复习和总结_第17张图片

查看分资源库分支

git branch -v用于查看分支情况

分支branch是这样的概念,你可以这样理解,就是一个资源库我们可以提交到git上去,首次提交上去如果没有指定分支,那么它默认是提交到master上面去;而其实一个资源库可以有多个分支,那么分支怎么理解呢,就是master是主干,从主干根据某次提交的版本分出来的一个新的git上的副本就是一个分支,比如我们master创建了,然后执行了三次,四次commit,我们可以从第三次commit那里创建一个分支,放到master下面独立的存在,这个分支和master是独立的,如果你后面有操作是只需要更新到master立马,这个branch是不会受到影响的,反之亦然。创建分支用命令:

git checkout -b branchname commitid

你可以看到我们没有创建任何分支的情况下,git上就只有master:


git的复习和总结_第18张图片

当我们执行checkout 分支命令后,可以看到多了一个分支:

创建分支的命令 git checkout -b newbranch f1af1affb65199fae这里后面的“f1af1affb65199fae”是从我们的log里面根据我们想要复制的commit id号随意提取的几位数字用以标记我们希望从什么版本checkout出来这个分支;

这样理解是不是就很好理解分支了,分支创建命令是checkout,从master的某个提交版本作为入口checkout一个分支来;

并且注意当前我们所在的分支也是刚刚创建的下图中绿色的newbranch这个分支目录下

git的复习和总结_第19张图片

当我们现在执行git log的时候就只能看到分支下面的日志,就是checkout出来的分支的下面本来有的日志:


git的复习和总结_第20张图片

如果我们需要查看所有分支的log,可以用git log --all 

或者git log --all -n2 --oneline --graph等结合方法来按返回每条日志中的第一行(--oneline),返回最近几2个(-n2)所有分支(--all)的图形界面(--graph)日志形式:

git log --all

git log --all -n4

git log --all -n4 --online

git log --all --graph


git的复习和总结_第21张图片

gitk图形化工具

我们前面都是在操作系统,非图形化的桌面界面的操作系统下,比如mac,linux等下面直接用命令行交互的方式来操作和管理我们的资源库的,需要一点点的Linux的命令基础,但是不多,一点点就行,比如如何进入目录,新建文件,vi修改文件等就够。

如果我们没有Linux的基础能不能用git呢,可以的,gitk就提供一个图形化的界面,可以从命令行直接输入 gitk 命令进入当前工作目录的git 图形界面

感兴趣的也可以直接去官网按图索骥小试牛刀:

https://riptutorial.com/git/example/18336/gitk-and-git-gui#:~:text=gitk%20is%20a%20graphical%20history,invoke%20from%20the%20command%2Dline.


git的复习和总结_第22张图片

.git目录

当我们执行 ls -la命令看到其实我们纳入git管理的资源文件夹下面是有些隐藏文件夹的,比如.git; .git文件夹特别重要,你在创建每一个git repository的时候都会在对应的文件夹下面产生这样一个目录。


git的复习和总结_第23张图片

那我们执行展开.git文件夹,看到里面有很多系统文件,我们主要关注HEAD,config这两个问题,HEAD文件里其实就是记录了当前我们所在的分支,而config里面保存者我们做的所有的配置数据,用户名等等;

我们cat Head一下看看里面的内容是一个ref 值是 refs/heads/newbranch,

我们还记得前面我们用git checkout -b newbranch f1af1affb65199fae新建了newbranch这个分支,当前的工作分支也是newbrach,那么会不会head就是记录的当前工作目录的分支呢:

我们用 git branch -va看一看分支情况:那么我们发现总共有两个分支,一个master,一个newbarnch,当前的分支就是在newbranch,那么HEAD文件里的也就是保存的当前工作目录的分支情况:


git的复习和总结_第24张图片

所以当我们回到工作路径下面执行 git checkout master命令把工作分支从新建的分支切换为master后,HEAD里面的记录也会相应的改变:

git checkout master 切换分支命令,要在工作目录下面执行。


git的复习和总结_第25张图片

那么config文件里有什么呢?

我们cat .git/config一下:可以发现其实config里面保存的信息是local的配置文件,我们可以修改local的信息,比如用户名等,然后再cat一下config观察是否有改变,这个不做赘述了,答案是肯定的。


git的复习和总结_第26张图片

.git目录下还有一个文件夹refs是比较重要的,里面包含了一些提交commit或者add命令执行后产生的对象,这个有空再更新。


如何删除分支?

当我们需要删除不再需要的分支的时候,执行 git branch -d branchname 命令删除分支,有时-d会要求使用 -D;

但是删除分支的时候必须是在其他分支下删除另一个分支,不能删除当前的分支;

git的复习和总结_第27张图片

如何对最近提交的commit操作的comments做变更呢?

有的时候需要对刚刚提交的commit的comments做一个变更:

git commit --amend

然后修改文本里的comments 保存退出即可:


git的复习和总结_第28张图片

那么如何修改之前的更以前的commit的备注message呢?

修改方式是,我们使用git rebase -i fathernodeid

比如我们现在要修改第一个commit的备注信息,那么我们用rebase -i 加上它的父节点也就是第二个commit的hash code随便一段唯一性的标志段都可以,然后你会看到它给你打开这样的一个文件,这里就记录了基于当前这个节点做的commit的操作,你可以看看下面有提供很多命令,对应不同的功能,我们只是想基于这个commit修改comments,那么我们把第一行的pick改成r 或者reword即可,它会跳转到对应的commit的comment记录页面,让你修改你的comment,修改完保存退出即可:


git的复习和总结_第29张图片

这是修改成功后的log:

如果你注意看变更信息,你会发现你修改了comment后实际上系统是用detached另一个分支出来 head-> bb0feb6 来对你对comment做变更,然后再用这个新的分支号替换掉原来的,所以现在你的master的hash code其实已经是变为新的了。


git的复习和总结_第30张图片

那么经过上面的git rebase -i pid 的方法,基于父commit来对后面的子commit来修改对应的操作的方法练习,我们应该能更深的对git的commit的结构有理解到,因此,我们试想一下这个场景,当我们想要合并最近的3个commit的时候,我们应该从那里切入去做对应的改变呢?答案显而易见,我们要找到倒数第三个commit的父节点,也就是倒数第四个commit,用rebase的方法,进去看看能做什么操作,能merge最好对不对:

你看这个节点下面有三个pick,表示基于这个commit后面又有三次commit操作,

那么我们仔细研读一下下面的命令,发现squash这个命令很合适,就是我们要保留commit的变更,但是合并到上一个commit里去,那比如我们这里有3个pick,我们把后面两个,第三次,第四次做的commit归并到之前的一个commit里去,就把下面的两个pick 改成 s,或者squash即可:

git的复习和总结_第31张图片

修改后保存退出;

git的复习和总结_第32张图片

这时候合并后,会跳出一个界面,我们为这次合并添加一点信息,我添加了一行comments标识一下这次合并:

git的复习和总结_第33张图片

当我们再次查看log的时候会发现多次留下的comments都还在,但是commit会减少2个:

同时我们可以观察到master的hash id又变化了,因为我们合并了两个commit,原来的master那个commit的父节点变了,所以他的id也变化了,这就是git的工作原理,当他的父节点指向别的commit的时候,通常是depatched一个新的分支,然后再把当前的分支指向新的父节点。


git的复习和总结_第34张图片

上面的情况是我们想把连续的几个commit合并为一个,我们可以找到他们最前面那个父节点,那如果我们想把最近的一个和前面间隔的一个commit合并怎么办呢,他们不连续了,如何操作呢?

我们可以这样做,比如我们要把最近的一条commit和与他相隔的一条commit合并,我们可以直接进入到这个要合并的这条commit里面,当然我们知道只能看到当前节点下面的commit,看不到他本身的,这个时候我们在最上面添加一个他自身的pick id;然后把要与他合并的那条commit记录移动到他下面,修改关键字 pick为s,把下面的这条合并到刚刚添加的那条记录里并删除多余的那条记录(下图的第四行要删除):

如果报错了,可以git status看看是什么原因,并根据提示继续操作。

试想一下,其实本质上就是rebase来修改或者合并两个commit。



git的复习和总结_第35张图片

比较缓存区和head里的内容差异

当我们修改里某个文件,使用add命令后,git首先把它放到缓存区里,此时我们可能会说有需要比较一下缓存区里的东西和head下面已经提交到git里的文档有何差异,double check一下:

我们使用git diff --cached来比较缓存区和head里面的文档的差异,我们看到绿色的那行变更是我们添加的东西,如果没有问题,我们可以提交,如果有问题我们可以继续修改这个文件:

git的复习和总结_第36张图片

那么如果我们要比较当前工作区和缓存区里有什么不通呢?这种场景比较常见,可能刚刚add了第一个文件,然后我们又修改了其他文件,但是还没有add,这个时候我们可以用 git diff直接查看到本地还有哪些修改了的文件与缓存区的不一样:(但是实际上用git status也是可以看到本地做了哪些修改的文件还没有add的)


git的复习和总结_第37张图片

那么既然又比较,当我们发现缓存区和head里的文件不通,也就是有add里一些东西,如果我们不想要这些缓存区的东西,要撤销,可以用git reset HEAD命令,撤销缓存区里添加的东西,检查是否撤销成功,可以用git diff --cached 来检查;

那么如果我们本地的工作区和缓存区有不同,比如我修改了本地工作区的两个文件,刚刚用git add -u 把他们都添加到缓存区了,那么我们现在又在工作区做了些变动,但是我们又觉得这些变动不需要,还是想和缓存区保持一致,那么可以用checkout加上具体的想恢复和工作区一样的文件名 这个命令来实现我们想要的效果:

发现确实是行的,再打开修改的文件检查一下,看刚刚添加的是不是撤销了,发现也是对的。

那么我们再来总结一下,我们又三个区,工作区,缓存区,head那边的管理区;如果我们想要把缓存区的东西撤销,和head保持一致,用reset命令,

想要单个文件,就加上文件名即可:git reset HEAD --filename

如果我们想要把本地和缓存区保持一致,用checkout,加上具体的文件:

git checkout --readme2 readme3 readme4.....(多个文件可以用空格隔开选择)

但是也要注意,checkout的时候少用,因为你一旦checkout了,也就是本地的修改就不见了,恢复就不容易了,而删除缓存区的东西是比较无所谓的,反正本地的东西还在。


git的复习和总结_第38张图片

如何消除commit

commit多次,然后我们发现可能有的commit是彻底不需要的,我们还是希望所有的东西都回到之前的某一个位置;比如我想撤销近两次commit,倒退到倒数第三次commit,:我们可以用 git reset --hard commitharshcodeid



git的复习和总结_第39张图片

然后我们就会发现它返回一条命令,说head指针已经指向我们想要的那个commit去了,那么你在用log看看,之前的两个commit已经不再了,而且用gitk界面工具也看不到那两个commit了:


git的复习和总结_第40张图片

如何比较两个不通的分支的差异呢?

比如我有master和checkout两个分支,如何比较他们的差异呢,其实还是可以用diff比较,我们知道diff其实就是比较commit的指针指向的位置,比如git diff commit1id commit2id;

同样的我们用 git diff branch1 branch2    它其实会去自动找branch的head指向的那个commit,然后做比较;

同样的道理,我们要比较一个branch下面的某个commit和另一个branch下面的某个commit的不通,只需要找到这两个branch下面对应commit的hash code的id就可以了(只需要理解,git它的工作逻辑就是对你每次操作commit的内容都给你一个唯一的hash code id,就是commit 后面跟着的那一串数字;如果有的提交和某次提交的内容是一模一样的,那么git会觉得你和那个commit是一模一样的,它不会再给你建立新的hash code id,会直接当成同一个东西);

如果只想看具体的一个文件,再命令后面指定文件名即可:

git diff master checkout --readme

git的复习和总结_第41张图片

删除文件 git rm filename 

如果我们不想要某个文件了,就是想以后提交到git的版本里都不需要这个文件了,我们可以直接用git rm filename删除,这个命令它会自动把删除的操作记录到缓存里去,并且在你下次commit的时候就不会再提交这个文件了。


git的复习和总结_第42张图片

当然如果我们想恢复撤销,可以用git reset --hard HEAD(这里的head也可以指定某个commit的hash code id);


git的复习和总结_第43张图片

.gitignore文件的作用

有的时候我们有些工作区的文件是不需要纳入到git里面去托管的,比如你用的react,npm管理工具里面的很多工具包是可以复现的,因此不需要专门放到git里面去,占用我们的空间;这个时候可以将这些不需要托管的文件放到一个.gitignore文件里说明一下,这些文件是不会被添加到git里面去的;

(这个需要再练习一下)

git的备份


git的复习和总结_第44张图片

我们常常为了保险起见,需要把远端的东西备份以下,可以用以下几中方法,我们先新建一个backup文件夹,然后把通过克隆的方式复制, --bare表示不克隆工作区,后面的/Git/existfile/.git  是你要克隆的远端的对应的工作目录路径加上/.git,这种固定形式是一种文件传输协议,记住使用即可;后面的 backup.git是你给克隆到本地的git文件的一个名称,

第二种与第一种的不通在于协议不通,第二种采用另一种协议(忘记啥协议了,智能协议吧)在克隆路径下多了 file:// 。

git clone --bare /Git/existfile/.git backup.git

或者

git clone --bare file:///Git/existfile/.git another.git

那如果试想下这个场景,我们回到我们的工作目录下,我们修改了一些东西,这些修改我们可以commit到git上去,但是我们如何快速同步到刚刚已经建立好的backup下面对应的git里去呢?

这个时候需要用到remote命令:

我们先用 git remote -v 看看当前的工作空间有没有建立远端的分支:

比如我当前的工作目录就还没有建立remote分支,那么我们用命令建立一个和本地相关联的remote的分支(其实是这样理解,比如我们是想把本地修改的任何东西和刚刚备份的那个地址下面的git联系起来,那么我们就需要用remote 命令把当前的工作目录和backup下面具体的git路径搭建一个桥梁,然后通过push把我们做的改变push到backup下面;之所以说remote或者远端,是因为这个backup可以是任何你想要建立链接的那个git,只不过我们当前就用backup下面的某个git来做的练习)

建立桥梁的命令是:我们就和another.git建立桥梁:

git remote add bradge2 file:///Git/backup-zexin/another.git

git git push --set-upstream bradge2 master 这条命令是基于刚刚建立好的bradge2上面,把我们当前的master branch push到远端的another.git里面去,需要注意的是,比如我们建立桥梁一定是从本地工作路径建立,然后在本地工作路径做push操作。

git的复习和总结_第45张图片


git的复习和总结_第46张图片


为了熟练操作这个远端的remote 创建bridge,然后通过push把本地的分支push到远端,可以反复多创建几个分支,一个个push,并查看是否成功。

GitHub

Github是一个非常热门的开源git的托管平台,在上面可以建立我们自己的git资源库,并且可以和本地通过git互相关联操作。

创建一个你的GitHub账号等等不多说。

现在在我的账号下面创建了一个练习repository :


git的复习和总结_第47张图片

我们现在尝试从本地的git工作目录把它push到远端的GitHub平台去,我们之前是做过远端的练习的,只不过现在我们把远端从backup下面的git换成了GitHub上面的repository;

我们在项目的左侧code处发现我们创建repository后它会自动生成一个远端的链接给我们,共我们使用:

https://github.com/tanzeytang/PHP-Exercise.git

git的复习和总结_第48张图片

同样的,我们为我们的GitHub上面的资源库新增一个远端的桥梁或者站点:

git remote add github https://github.com/tanzeytang/PHP-Exercise.git


git的复习和总结_第49张图片

然后我们执行 git push github --all 尝试把这个创建的桥梁站点push到GitHub上面去,但是我们会发现它报错了,因为我们创建repository的时候不是一个空的repository,已经有一些文件了,而且这些文件本地没有,那么直接push就会报错,这是我们只需要先用fetch把GitHub上的东西下载到本地,然后再从本地push到GitHub上去:


git的复习和总结_第50张图片


那么我们先fetch以下,git fetch github master 把刚刚从远端创建的桥梁下的master分支fetch 到我们的工作目录下;然后我么可以打开gitk --all查看以下现在的所有的分支树情况。其实我们会发现用git fetch github master执行命令后,远端的master和我们本地的所有分支其实是两个独立的树,也就是根本没有啥相互的联系;


git的复习和总结_第51张图片

那我们怎么把远端fetch过来的master分支和本地的树联系起来呢,我们需要merge以下:git merge github/master

我们发现它会报错

因为我们从远端fetch过到本地工作目录下面到这个分支 github/master这个分支和我们本地到所有分支是独立的两颗树,git不允许直接merge到本地的当前工作的branch也就是master分支下;

我们用 这样一个命令试试,允许不想干的分支merge到当前分支:

 git merge --allow-unrelated-histories github/master 

这样就不会报错了 它会跳转到一个commit comments编辑页面,让你对此次merge写一个备注:


git的复习和总结_第52张图片

那么我们现在再来看看gitk上面的分支关系,你发现当前的master分支和远端的master链接上了:


git的复习和总结_第53张图片

此时我们再执行 git push github --all 把本地的文件push到远端上去就没有问题了:


git的复习和总结_第54张图片
git的复习和总结_第55张图片

同时我们执行了push以后,会发现远端的master也指向了本地的master了:


git的复习和总结_第56张图片

多人协同操作git

现在来模拟多人同时对同一个git下面的分支做操作,你可以修改,我也能修改,以及如何处理我们协作中可能遇到的问题等;

先做三件事情,第一件事是在GitHub上我们上面创建的repository下面新建一个分支:abranch;

第二件事情是用git clone https://github.com/tanzeytang/.... 先复刻到我们本地工作目录的上一层目录;此时多了一个克隆下来的 PHP-Exercise文件夹

第三件事,再克隆到同路径下的不同文件夹下:git clone https://github.com/tanzeytang/.... 

git的复习和总结_第57张图片

那么我们现在有以下目录:


git的复习和总结_第58张图片

这样做是为了模拟我们有两个用户在操作这个git库,我们本地的工作目录是existfile;我们克隆的第一个工作目录是 PHP-Exercise 然后第二个克隆的目录是PHP-Exercise2,我们可以用git config 命令把PHP-Exercise2的username user.email设置以下,设置为其他的email,以此标记为不通的用户:

git config --add --local user.name 'xiaoxiong'

git config --add --local user.email 'ztan.....'

我们可以用git config --local -l命令查看是否修改成功了


git的复习和总结_第59张图片

同时我们看下现在的工作环境下我们的branch有下面这些:


git的复习和总结_第60张图片

现在我们做一件事情,我们用这个用户去基于远端的abranch分支新建且切换到这个分支:

git checkout -b abranch origin/abranch


很好,那么现在是xiaoxiong工作在PHP-Exercise2工作目录下的abranch分支(相当于你的同事工作在它的本地目录下的从GitHub上复刻下来的abranch那个分支),然后以xiaoxiong的身份修改了README.md文件;

然后add,commit到git,因为git创建这个本地分支到时候是指明从远端 origin/abranch的,所以我们把修改的文件提交给git的时候,它也会同时同步给远端关联的那个abranch分支,但是还需要push到远端去,

执行git push命令可以把当前git上作出到修改也同步push到关联到远端上去:


git的复习和总结_第61张图片

你可以去GitHub上看看也能看到abranch分支下面的文件被xiaoxiong修改了:


git的复习和总结_第62张图片

模拟第二个用户的工作状态,现在我们切换到之前到工作目录existfile下面,这个目录我们做到所有操作包括,一开始到从GitHub上fetch了当时创建GitHub资源库到那两个文件,然后把本地到分支push到GitHub上,但是abranch是后来的人直接在GitHub上面创建的,所以existfile工作目录下没有这个分支,我们需要把abranch fetch下来:

因为我们之前创建过github这个桥梁,所以可以直接从这里fetch所有的分支即可:这个命令实际上是把GitHub上面新建的那个分支给fetch下来了:


git的复习和总结_第63张图片

要注意的是,我们从远端fetch也其实只是相当于构建了一个中间联系,如果要在本地对新增的那些文件做一些操作,还是要用git checkout -b abranch github/abranch 在本地创建一个分支并且切换过去:

现在我们工作在本地的abranch目录下:


git的复习和总结_第64张图片

我们来捋一捋,现在我们有两个用户都把远端GitHub上都repository通过fetch 建立都链接,然后一个是克隆到本地,一个是把本地到push到远端;

现在远端新建来一个分支abranch,我们两边都通过fetch先把分支建立联系,然后通过git checkout 把abrach check到本地,xiaoxiong先修改了一些东西,第二个用户在小熊提交到git,再push到GitHub后,第二个用户再次fetch了一次GitHub到桥梁,然后再把桥梁里到abranch通过check 命令check 到本地到同名分支abranch。

现在两个用户都能对远端abranch分支进行操作,我们试试创建一个confilic,我们先让第二个用户修改一点东西,readme.md里对东西;先不提交,也不着急push到GitHub上,此时如果xiaoxiong先一步对其他文件做了修改然后提交到git后又push到了GitHub上,我们再让第二个用户提交,可以想见这里肯定会有问题,看看如何处理这样到情况,因为这是git团队协作到时候非常常见到场景:

这两边的操作不再赘述,小熊提交到GitHub上可以看到他先一步做了修改:


git的复习和总结_第65张图片

那么我们现在第二个用户再对readme.md进行提交的时候,就会报错:


git的复习和总结_第66张图片

我们还是用fetch 命令从远端把本地没有更新的那部分fetch到本地的github桥梁下:

现在我们用git branch -va 查看一下分支情况,

你会看到你本地目前的这个abranch分支后面有一个ahead1,behind1,意思是说,你的分支和远端相比较,有一个是你有的远端没有,有一个是远端有的,你没有;

git的复习和总结_第67张图片

那么这种情况呢,我们可以考虑采用merge来解决:git merge github/abranch

因为我们如果不是修改的同一个文件,那么我们合并以下就可以了对不对,合并 然后我提交我的,不影响,本地会有一个文件你没有更新的那个会合并进来,比你新文件的会更新到你的本地进来。然后你git push以下就会成功;

但是如果我们是修改的同一个文件呢的不通地方呢?

首先可以用git pull把远端的文件同步到本地来以下:

然后我们创建这样一个场景,就是两个人对同一个文件做来修改,但是有一个人小熊先提交了。

那么我们看看第二个用户提交的时候会怎么样?

还是会被无情拒绝,解决这样的方式可以是,我们还是可以先fetch,然后merge,git会自动的把同一个文件中你没有修改的,别人有的那部分merge到你的 文件中,然后你再push。

但是如果我们是修改的同一个文件下的相同区域呢?

首先都是会被无情拒绝,直接来到如果解决这个问题这一步:

首先如果是同一个文件同一个地方,git就无法自动的区分是谁的文件里哪部份更新或更旧,所以git无法替我们做选择,我们需要人为的介入,还是假设小熊先提交,第二个用户再来修改的同一个地方;

当我们merge的时候,git会和远端进行对比,发现你们修改的是同一个地方,就会报错了,conflict:


这种情况下,我们要人为的鉴别以下,打开这个文件:《《《《《HEAD

中间的这些都是你们冲突的内容

 》》》》》github/abranch

:我们可以对这个文件进行编辑,和同事协商一下怎么改一下,达成一致意见后,我们在本地重新 add,commit,push就可以了;


git的复习和总结_第68张图片


git的复习和总结_第69张图片

在GitHub上也能看到同步修改到结果:


git的复习和总结_第70张图片

如果其他人修改了文件名怎么办?

先在我们还是到刚刚到两个用户下面去,首先总结经验教训,先把自己到分支和远端到进行同步一下:git pull就可以了,pull命令首先会把远端到fetch下来,然后和你本地到merge一下,保证你到和远端是一致的;

然后我们让小熊去把其中一个readme2文件修改为readme3并立马提交到远端了:

git mv readme2 readme3

git add -u

git commit -m 'modify filename'

git push


与此同时,第二个用户去对readme2进行了修改并尝试push;

不出所料的报错了,根据提示信息我们执行git pull,然后发现git可以很智能的发现你和对方的区别是名称,所以就自动给你把名字更新了:


git的复习和总结_第71张图片

如果多个人都在修改同一个文件名呢?

看到很多人的版本说是当两个人同时修改同一个文件名,如果他先提交了,你这边会z在status下面看到原来的文件名以及被删除了,对方提交的文件名,以及你自己的修改的文件名;但是我自己操作的时候发现是没有的,但是你可以通过pull 把人家的也同步过来,我感觉我那里做的有问题,因为这样做很不合理,如果不告诉我名字改了,如果我先pull了,岂不是很容易无法发现这样的情况?再试一试?


git的复习和总结_第72张图片

我这边暂时智能通过 删除本地不需要的那个文件,然后add,commit,push到远端,达成解决conflict,但是感觉很不舒服,因为我始终没有得到git的任何一点点提示说别人也修改了文件名。

至此git的复习操练就差不多了,后面还会再结合GitHub上多个用户协同操作的联系一下应该就够用了。

你可能感兴趣的:(git的复习和总结)