赞
踩
寒假在昆明呆了3天,因为闲着没事做,所以把Git教程看了看。鉴于之前学习python不懂得整理,导致后来选择性遗忘没。所以就抽出一天时间来,整理一下Git的一些常用命令和自我理解的通俗性语言。
Git是一种分布式版本控制系统,顾名思义,就是每个人的计算机都是一个完整的版本库,它允许多人进行协作,是因为它强大的分支管理(后面会提及),而不是像集中式那样,只有一台中央服务器,其他计算机需要进行开发时,必须向中央服务器申请。一旦中央服务器出现了宕机,项目进度就只能被迫停止。总而言之,Git方便代码管理,为协作编程和进行版本控制提供了极大便利。
Git可以在Windows上跑,也可以在Linux上跑,当然其他操作系统也可以。本次我安装在Windows上。首先去Git官网下载、默认安装。成功之后,在开始菜单找到Git Bash,OK安装成功
我所理解的Git的使用是在服务器(也就是自己的计算机上),可以建立多个仓库,每个仓库对应一个项目,仓库=U盘嘛。别人可以clone你的仓库,修改你的代码,你也可以在对代码进行版本控制(比如发布v1.0、v2.0)和游戏版本一样。
1.1建立仓库
所以首先我们先创建一个文件夹:
- mkdir <仓库名>
- cd <仓库名>
- pwd //密码
然后将它变成Git可以来管理的仓库
git init
OK,Git就把仓库建好了。
1.2 提交文件到仓库
在该文件夹下编写一个.txt文件
vi readme.txt
然后通过git add,将文件从工作区添加到仓库中的缓存区(stage)中,
git add readm.txt
再通过git commit,将文件从缓冲区中提交到仓库中
git commit -m "我写了一个readme,厉害不" //-m是本次提交说明
补充一点,最好“”里面的
文字用英文代替,中文很容易乱码,我在这纯属以后方便记忆。
总结一下:(我就直接用廖雪峰老师的话来代替了)
初始化一个Git仓库,使用git init
命令。
添加文件到Git仓库,分两步:
使用命令git add <file>
,注意,可反复多次使用,添加多个文件;
使用命令git commit -m <message>
,完成。
假设我们对readme.txt 做了多次修改,要是我们想还原到某一次修改的地方,我们应该怎么找到那一次修改呢?用git log
git log
然后在git log 里找到你对应版本的地址,16进制的,通常你输入前面几个,Git就会自动找到该版本。但我墙裂建议用
git log --pretty=online //超级清爽有木有
现在,我们要回退到比如&simple版本
git reset --hard a065af
现在再查看readm.txt 的内容
cat readme.txt
就回发现已经到那一个版本了。
还有一种办法,因为在Git中HEAD指针始终是指向最后一次commit的,要是只想回去上一次,可以这样操作:
git reset --hard HEAD^ //回退到上一个版本
ok,继续借用老师的总结:
HEAD
指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset --hard commit_id
。
穿梭前,用git log
可以查看提交历史,以便确定要回退到哪个版本。
要重返未来,用git reflog
查看命令历史,以便确定要回到未来的哪个版本。
git checkout -- file
可以丢弃工作区的修改:
git checkout -- readme.txt
命令git checkout -- readme.txt
意思就是,把readme.txt
文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt
自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt
已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit
或git add
时的状态。
但是会有这么一种情况:你修改了文件,而且还将它add到了缓存区了,但还没有提交。这时候,可以把缓存区的修改撤销掉,重新放回工作区:这需要2步
1、
git reset HEAD readme.txt
2、
这时候,再丢弃工作区的修改:
git checkout -- readme.txt
OK,又到了小结时间:
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file
。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD <file>
,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
在本地的文件,可以直接用rm命令删除:
rm test.txt
这时候,Git知道你删除了哪些文件(通过git status 可看出),此时,工作区和版本库就不一致了。如果你要从版本库中删除该文件,这样做:
- git rm test.txt
- git commit -m "remove test.txt"
现在,文件就从版本库中删除了。
但如果是误删了,可以从版本库中恢复最新的:
git checkout -- test.txt
PS:写总结可真累了,总算把第一部分写完了,明天抽空接着写最重要分支管理叭
昨天总结完了Git的一些“增删改查”,今天开始总结一下分支。
我所理解的分支是:假设一个项目是一条主线,它是由各个功能板块(函数?)构成的,假设没有分支的存在,那开放人员就只能像队列一样,等待前一个人处理完后,后一个人才能开始工作。但有了分支之后,每一个人就能够在自己的分支上开始工作,互不影响,最后大家再把各自的任务整合到一块,就可以形成一个完整的项目。
在Git中,主分支默认为master,也可以理解为master是指向主分支的最后一次提交,HEAD指针指向master。
当我们创建一个分支dev的时候,HEAD指针就会指向dev,此时对工作区的修改和提交都针对Dev,对dev进行一次commit,dev指针就会向前一步,而master指针始终不变。
当我们将dev合并到master上时,直接将master指针指向dev当前的提交就OK啦。
合并结束后,我们可以将dev删掉,此时就只剩master了。
图解结束后,我们直接上代码:
3.1.1、创建分支:
git checkout -b dev
其中,-b参数表示创建并切换。相当于
- git branch dev
- git checkout dev
事实上,我们注意到切换分支使用git checkout <branch>
,而前面讲过的撤销修改则是git checkout -- <file>
,同一个命令,有两种作用,确实有点令人迷惑。
实际上,切换分支这个动作,用switch
更科学。因此,最新版本的Git提供了新的git switch
命令来创建并切换分支:
git switch -c dev
直接切换到master分支,也可以用:
git switch master
可以用git branch 来查看分支:
git branch
当我们在dev完成工作后(指commit之后),可以将其合并
git merge dev
接着删除dev
git branch -d dev //-d表示delete
现在做一个小回顾:
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch <name>
切换分支:git checkout <name>
或者git switch <name>
创建+切换分支:git checkout -b <name>
或者git switch -c <name>
合并某分支到当前分支:git merge <name>
删除分支:git branch -d <name>
本节得含义是:创建了一个feature1分支,修改其中得内容(比如readme.txt),假设修改内容是“1”,commit了之后。再切换回master分支,再将master分支上的同一内容(比如readme.txt)改为“2”,此时,feature1和master分支都有了新的提交,如图所示:
这种情况下,因为feature1和master上的readme.txt不一样,将他们合并时,会产生冲突,此时就需要手动来解决冲突,然后再提交。同时,通过git status 也可以查看冲突的文件。
手动解决冲突的过程:将内容(readme.txt)改为我们所希望改的内容,再重新add+commit,就行,如图解:
git branch -d feature1
小结
当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交。
用git log --graph
命令可以看到分支合并图。
3.3.1 分支管理策略
上述说的分支合并是修改了master的指针,在Git中是Fast forward模式的,在删除分支后,会丢掉分支的信息。接下来说的是强制禁用Fast forward模式,Git会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
实践如下:
首先创建并切换dev分支
git switch -c dev
修改内容(readme.txt),并提交一个新的commit:
- git add readme.txt
- git commit -m "add merge"
现在,我们切换回master:
git switch master
用 --no-ff 来合并dev分支:
git merge --no-ff -m"merge with no-ff"dev //no-ff 表示no-Fast forward
这时候,merge后的就像这样:
所以,合并分支时,加上--no-ff
参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward
合并就看不出来曾经做过合并。
总结一下:
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev
分支上,也就是说,dev
分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本;
你和你的小伙伴们每个人都在dev
分支上干活,每个人都有自己的分支,时不时地往dev
分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
假设现在来了一个bug,需要紧急修复,但你在dev上的工作没有完成,可以使用:
git stash //保存现场工作
然后在master上创建一个新的分支比如(test1)来修改BUG,等bug修复完成后,再合并,并且删除该分支(test1)。一切都结束之后,就可以继续进行自己先前保存的工作了
首先,先转向dev分支
git switch dev
接着,用git stash list 命令看看保存的工作现场去哪里了:
git stash list
可以看出,我的dev在 11b7546这个位置。
恢复现场办法有两个,第一种方法是
git stash apply
恢复之后,但stash内容并没有删除,可以使用
git stash drop
来删除。
第二种办法是直接使用:
git stash pop //恢复现场+删除stash里的内容
此时,用
git stash list
就看不到任何stash内容了。
刚才说的bug是在master上,照理来说我们现在工作的dev上也会存在同样的bug,那我们怎样用优雅又快速的方式来修复这同样的bug呢?
方法:只需把特定的提交merge到当前的分支即可。也就是说,我们把刚才对该bug的修改复制到dev分支上。注意:我们只想复制修改那个bug这个提交所做的修改,并不是把整个master分支merge过来。
Git提供了这么一个方法
git cherry-pick 4c805e2 //4c805e2是提交之前bug修改的commit的地址号
用git cherry-pick
,我们就不需要在dev分支上手动再把修bug的过程重复一遍。
小结一下:
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash
一下,然后去修复bug,修复后,再git stash pop
,回到工作现场;
在master分支上修复的bug,想要合并到当前dev分支,可以用git cherry-pick <commit>
命令,把bug提交的修改“复制”到当前分支,避免重复劳动。
今天出去玩了,导致现在才写完,果然我的效率还是太低,也还有很多事情没做完。加油啊,明天争取搞完Git。就开始全身心搞编程啦,加油!老温!
新建了一个分支之后,处理完之后,要是并没有合并,用
git branch -d 分支名
这样,我们只能用-D来强行删除:
git branch -D 分支名
这一节只有这一个知识点。
远程仓库的默认名称是origin。假设你想查看远程库的信息,可以用:
git remote
也可以用
git remote -v //显示更详细的信息
推送分支:
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
git push origin 分支名
PS:并不是本地所有的分支都要远程推送的。
master
分支是主分支,因此要时刻与远程同步;dev
分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;抓取分支:
//push 推送 pull 抓取
这一节需要两台电脑来协助,因为条件允许,我就大概描述一下这一节所要表达的意思。
假设你和你的另一个同事同时在同样的分支和同样的文件上操作,当他提前push到远程端,你push的文件就会和他产生冲突,解决冲突的办法很简单,就是通过git push把最新的提交从远程端抓(pull)下来。然后再本地合并,解决冲突,然后再push。
git pull
这时候会发现,git pull也失败了,原因是没有指定本地dev
分支与远程origin/dev
分支的链接,根据提示,设置dev
和origin/dev
的链接:(这里解释一下,这里是假设我和同事都是抓取dev来进行修改的)
git branch --set-upstream-to=origin/dev dev
再pull
git pull
这回git pull
成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:
- git commit -m "fix env conflict" //先提交到本地版本库
- git push origin dev //再push到远程端
因此,多人协作的工作模式通常是这样:
git push origin <branch-name>
推送自己的修改;git pull
抓取下来,试图合并;git push origin <branch-name>
推送就能成功!如果git pull
提示no tracking information
,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
查看远程库信息,使用git remote -v
;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用git push origin branch-name
,如果推送失败,先用git pull
抓取远程的新提交;
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name
,本地和远程分支的名称最好一致;
建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
;
从远程抓取分支,使用git pull
,如果有冲突,要先处理冲突。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。