Git

Git是分布式版本控制系统,SVN和CVS是集中式版本控制系统。

集中式和分布式的区别?

 

使用方式:

1.建一个空文件夹(或者说一个目录)learnGit,不一定要是空的

2.git init把这个目录变成git可以管理的仓库

所有的版本控制系统,都只能跟踪文本文件的改动,txt,网页,程序代码等。图片,视频属于二进制文件,也能用版本控制系统管理,但是没法跟踪文件的变化,只能知道改了多少数据量(比如10k),但是不知道具体改了什么

微软的word是二进制格式,所以不能用git管理。

编码问题,强烈建议使用标准的UTF-8编码!

不要使用微软自带的记事本编辑文本

 

写好一个文件,比如readme.txt在learnGit下,cd 到这个目录,然后git add readme.txt,把文件添加到仓库

然后git commit -m “worte a readme file”

-m后面是本次提交的说明

一句commit可以提交多个文件,比如add了两个文件进去,commit一次提交多个文件。

之后我们修改了readme文件的内容,这个时候再git status,这条命令可以知道当前仓库的状态,比如这里是readme被修改了,但是没有提交

要如何看到到底修改了什么内容呢?git diff readme.txt,可以看到变化的是git is free变成了git is a free software

git status 查看有哪些改动

git dff 查看改动的具体内容

知道修改了什么,觉得没问题,可以提交就可以add进仓库了,然后再git status查看一下,Git提示将被提交的是readme

然后commit后,再git status,可以发现就没有要待提交的文件了,工作目录是干净的 working directory clean

版本回退

然后不断的修改,用git log可以查看查看历史记录

log太长可以可以加上--pretty=oneline查看精简版的log,前面长串的“乱码”是commit id(版本号),这个东西通过SHA1计算出来的

当前的readme是这样的

要如何回到之前的版本呢?要回滚Git必须知道版本号,Git用HEAD表示当前版本,上一个版本叫做HEAD^,上上个版本叫HEAD^^,往上100个版本叫做HEAD~100

 

再git log的时候,发现少了append GPL那条了,那我又后悔了,要如何再滚回来呢?这个时候如果命令行没有关闭,是可以查到之前的append GPL对应的版本号的,然后就可以reset了

注意:版本号可以不用写全的,比如这里本来是05a870e,但是我只打了05a8也是可以的。现在readme又回到有GPL的这个版本了。那如果命令行已经关闭了,要怎么办?

用git reflog,清楚的记录了每一次命令,这里从前面三条可以看到滚回到前一个版本,然后又滚回来,然后又滚回去,所以现在readme是上一个版本,下面的第四条可以看到GPL这个版本的版本号,

有了版本号就可以再滚回最新版本了

git log和git reflog的区别?

git log可以查看提交历史(只有commit)

git reflog可以查看命令历史(比如会包括reset这种)

版本回滚的原理是Git内部有个指向当前版本的HEAD指针,在回滚的时候,git只是移动下这个指针,然后把工作区的文件改了而已

 

 

暂存区

工作目录Working Directory,就是电脑里能看到的目录,比如learnGit这个文件夹

版本库repository,工作目录下的.git隐藏目录就是版本库,版本库里放了很多东西,最重要的就是叫做stage的暂存区,Git自动创建的master分支,以及master的一个指针HEAD

git add实际上是把文件添加到暂存区

git commit把暂存区的所有内容提交到当前分支

也就是说如果修改了但是没有add到暂存区,那么commit的时候就不会commit这次的修改

 

撤销修改

这时,修改了readme,然而没有add进暂存区,然后发现这个修改不行,可以checkout -- filename来撤销掉这次的修改

如果已经add到暂存区了,要撤销这个修改,要先把暂存区的这个修改unstage,重新放回到工作区。

使用git reset HEAD file

下图可以看到,本来readme的修改是Changes to be committed,变成了Changes not stage for commit

也就是说这个修改已经滚出暂存区回到工作区了,然后再像之前说的checkout -- file就可以将这个修改撤销掉了

如果已经commit了,那么就用之前的 git reset --hard commit_id 来回滚

 

删除文件

删除也是一种修改。比如,新建一个test,然后提交。

删除可能出现在资源管理器中删除,或者rm,这个时候Git知道你删掉了文件,工作区和版本库就不一致了,再git status就会看到哪些文件被删除了。

这个时候有两种选择(情况):1.确实是要删掉;2.删错了

如果确实要删掉,那么git rm test,然后git commit,这样就可以把版本库里的删除掉了

如果删错了,因为版本库还有一个,所以可以用git checkout -- test恢复。这里的恢复就是将版本库里的版本替换中工作区的版本,无论是修改还是删除,都可以这样干

注意rm和git rm的区别

rm删除一个文件,操作的是工作区的。

git rm是提交一个操作(rm)到暂存区,然后再commit这个操作到版本库(可以在执行该命令后通过git status来查看),这样Git就把版本库里的对应文件删除了。再执行这个命令的时候,会自动执行rm,也就是说会自动把工作区的文件删除了。

 

远程仓库

远程仓库有两个用处:代码备份,协作完成

1.先有本地仓库

在GitHub点击New Repository新建一个仓库。Repository name填learngit

cd到learnGit文件夹:

将本地仓库跟远程仓库关联:git remote add origin https://github.com/Yuijam/learngit.git 

把当前分支推送到远程:git push -u origin master

再刷新一下远程库,就可以看到本地提交过去的东西了

2.先有远程仓库

新建一个仓库gitskills,勾上初始化README选项,其余默认

克隆到本地:$ git clone https://github.com/Yuijam/gitskills.git 

 

GitHub提供两种协议,SSH和HTTPS,SSH我没有成功,可能是公司网络端口的问题?

据说SSH比较快,HTTPS比较慢,而且每次push都要输入口令

 

分支

HEAD严格的说不是指向提交,而是指向master,master指向提交,HEAD指向的是当前分支

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长

这个讲得很清楚了

http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/001375840038939c291467cc7c747b1810aab2fb8863508000

 

新建一个分支。-b参数表示新建一个分支并切换到这个分支,相当于两条命令 git branch dev , git checkout dev

使用git branch查看当前分支。会列出所有分支,打*号的是当前分支

修改readme并提交,然后切换到master,发现readme没有变,因为是在dev分支上改变的,所以当然没有改变

用git merge dev将dev分支合并到当前分支,也就是master,再查看一下readme发现确实改变了,然后删除掉dev分支。Git鼓励使用完分支后,合并代码,然后删掉分支这种做法,因为过程安全。

 

处理冲突

合并并不会总是一帆风顺

新建一个分支 featurel并修改readme,然后add,commit。

再回到master分支,修改readme,add,commit。

合并两个分支,出现冲突,并且指明了是在readme,这个时候git status可以看到具体情况,都修改了readme。注意到这里由(master)变成了(master|MERGING)

那么怎么办?

要处理完冲突再提交。可以直接查看到readme的内容变化了,Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容

然后修改好readme,commit提交即可。用git log --graph --pretty=oneline --abbrev-commit可以查看到分支的合并情况。

 

分支管理策略

再新建并切换到dev分支,修改readme(注意,这里就只在下面添加一行hhh,如果在内容里面改,下面就需要处理冲突),并add,commit

切换到master,git merge dev合并。注意这里切换回master后并没有修改什么东西,也没有提交什么东西。

看到log有点奇怪,居然少了分支信息!!!

要怎么才能看到做过合并呢?

git merge --no-ff -m "merge with no-ff" dev

这样就看到分支历史了。原因是合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

--no-ff参数,表示禁用Fast forward。如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息

 

Bug分支

有这样一种情况,你在dev分支下做某个功能,做到一半,接到一个任务,处理一个bug,比如这个bug是在master分支下的

这个时候因为代码没写完,不好提交,然后又要去处理那边的bug,怎么办?可以用git stash把工作现场储藏起来,等之后恢复现场后继续工作。

这里readme修改后没有add,在git stash后再查看git status发现工作区已经是干净的了。

然后再切换到master分支,新建一个issue101的分支来修复bug(这里用在readme里面添加一行 fix bug表示),然后add,commit后再切换到master,合并分支,然后删掉issue101

这个时候bug修复好了,就可以回来继续之前dev的未完成的工作了。

通过git stash list来查看之前的工作现场。要恢复有两个办法:

1.用git stash apply来恢复,但是恢复后,stash内容不会删除,要继续用git stash drop来删除

2.用git stash pop来恢复,恢复的同时把stash内容也删除

这里用git stash pop恢复,然后再git stash一下发现里面没有东西了

git status可以看到工作区的内容恢复了。

当有多个stash时,也就是list里面有多个时,可以用git stash apply来指定要恢复哪个

 

git branch -D branch-name 来删除未合并的分支,注意这里是大写的D,写d没用

 

多人协作

远程仓库的默认名是origin

查看远程仓库的信息,用git remote

git remote -v 可以显示更详细的信息:

下面显示了可以抓取和推送的origin地址。

推送分支

git push origin master 表示把本地master分支推送到远程origin仓库

也可以推送其他分支,比如 git push origin dev

并不是所有分支都要推送过去,视情况而定, 比如bug分支

 

当从远程clone时,默认情况下,只能看到本地的master分支,比如远端有一个dev分支,clone过来git branch一看发现只有master一个分支

用 git checkout -b dev origin/dev 创建远程origin的dev分支到本地,这样就可以继续在dev下修改了

如下图

当你在dev做了修改,比如修改了readme,添加了一句 linux edit,add commit 没问题。

这个时候准备push的时候,如果有人也修改了dev的readme,然后push上去了。这个时候你去push就会出问题,如下

git提示需要git pull,那么就git pull一下,结果发现自动合并失败。要处理冲突,处理冲突

解决冲突的办法跟之前解决冲突一样的,也是修改了readme后,add,commit,然后再push就没问题了。

 

因此,常用的步骤是这样的:

1.首先,尝试用git push origin branch-name来推送自己的分支的修改

2.如果推送失败,则远程分支比你的本地要新,那麽就用git pull尝试合并

3.如果合并有冲突就解决冲突,然后在本地提交

4.解决冲突或者没有冲突就可以用git push origin branch-name推送了

如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令

git branch --set-upstream branch-name origin/branch-name

 

标签管理

发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。

Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。

 

打标签步骤:

1.切换到要打标签的分支

一般是master?master代表着要发布的稳定版本。dev也是可以的。

2.git tag v1.0

这样就打了一个标签。默认标签是打在最新提交的commit上的,如果要打以前标签,怎么打?也就是说要怎样给指定的commit打上标签

方法是找到历史提交的commit id

用 git log --pretty=oneline --abbrev-commit 查看到历史commit,找到要打tag的commit id

然后git tag <tagname> <commit-id>就可以了

 

git tag可以查看所有标签

git show <tagname>可以查看标签信息

创建带有说明的标签: git tag -a v0.1 -m "version 0.1 released" <commit id>

 

删除标签

git tag -d v0.1

tag不会自动推送到远程,所以这里可以在本地删除。

推送标签到远程

git push origin <tagname> 

如果tag已经推送到远程了,这时要删除就要这样搞

1.先把本地的tag删除了

git tag -d v1.0

2.再把远程的删除了

git push origin :refs/tags/v1.0

可以到github上的release那里看看是否真的删除了

 

忽略文件 

提交的时候有些比较重要的文件,比如各种key什么的,密码什么的不希望提交,这个时候怎么办?

1.在工作区新建一个 .gitignore 文件,把要忽略的文件名填进去,Git就会自动忽略这些文件了

比如在文件里写上:

*.txt

Git在就会把txt忽略掉

 

配置别名 

单词太长?那就取个别名

比如用 co代替checkout ,用 br 代替 branch,可以这样写

git config --global alias.co checkout

git config --global alias.br branch

--global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用

在撤销修改一节中知道,git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回到工作区。既然是一个unstage操作,就可以配置一个unstage别名

git config --global alias.unstage 'reset HEAD'

这样当敲 git unstage test.py 

实际执行的就是 git reset HEAD test.py

 

配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用

每个仓库的Git配置文件都放在.git/config文件中

 

当前用户的Git配置文件放在用户主目录下的一个隐藏文件 .gitconfig中。如下图,可以看到里面包含了之前设置的别名,所以配置别名也可以直接修改这个文件。或者从这个文件中删除别名。

 

posted @ 2017-04-17 12:07  Steve_Nash  阅读(151)  评论(0编辑  收藏  举报