您的位置:首页 > 其它

Git的简单使用教程

2017-03-29 21:21 344 查看

Git的安装

Linux下

直接sudoapt-get install git-core

Windows下

直接下载安装 https://git-for-windows.github.io/


安装完成后,还需要最后一步设置,在命令行输入:

$ git config –global user.name “Your Name”

$ git config –globaluser.email “email@example.com”

设置名称和邮箱是为了在提交代码的时候知道是谁提交的。

创建版本库

版本库又名仓库,可以简单的理解为一个目录,这个目录里面所以的文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来的某个时刻可以还原。
创建仓库只需要在需要变成仓库的目录下输入 gitinit
创建完后这个目录下会出现 .git 的目录,这个目录是用来Git来跟踪管理版本库的。
如果要删除这个仓库只需要将这个目录删除掉。


在Linux下建立目录并设置为Git仓库的代码:

mkdirlearngit

cdlearngit

gitinit

(显示当前目录) pwd

把文件添加到版本库

注意:千万不要使用Windows自带的记事本编辑任何文本文件。原因是Microsoft开发记事本的团队使用了一个非常弱智的行为来保存UTF-8编码的文件,他们自作聪明地在每个文件开头添加了0xefbbbf(十六进制)的字符。

建议使用notepad++代替。

将文件添加到仓库:

第一步,用命令git add告诉Git,把文件添加到仓库:

git add //git add readme.txt

第二步,用命令git commit告诉Git,把文件提交到仓库:

git commit -m “wrote update info”

简单解释一下git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。

为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

$ git add file1.txt

$ git add file2.txt file3.txt

$ git commit -m “add 3files.”

$ git add . —>代表将所有文件进行添加

小结

初始化一个Git仓库,使用git init命令。

添加文件到Git仓库,分两步:

l 第一步,使用命令git add ,注意,可反复多次使用,添加多个文件;

l 第二步,使用命令git commit,完成。

Git查看文件的更改

当我们将文件内容进行更改后可以用git status命令查看结果。

git status命令可以让我们时刻掌握仓库当前的状态

我们可以使用git diff命令查看我们修改了什么。

git diff git diff顾名思义就是查看difference

小结

l 要随时掌握工作区的状态,使用gitstatus命令。

l 如果gitstatus告诉你有文件被修改过,用git diff可以查看修改内容。

版本退回

我们可以用git log命令查看修改历史。

git log命令显示从最近到最远的提交日志,如果输出信息太多可以加上

–pretty=oneline参数。

git log–pretty=oneline –>显示信息为:版本号(commit id)和git commit -m提交时设置的提示说明。

首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新提交的commit id为3628164…882e1e0,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。

我们使用 git reset命令来进行版本的回退。

git reset –hard HEAD^ —->返回上一个版本

也可以是 git reset –hard HEAD~1

(Windows系统下 git reset –hard HEAD^^ 才会返回上一个版本)

然后 stackoverflow 解释:If you’re using Windows, you could do git log HEAD^^, I believe. – Name McChange Nov 4 ‘13 at 0:58 The ^ is an escape character in the Windows Command Line. Use ^^ instead of ^.

其他解释:在windows的命令行中 git reset -hard HEAD^ 中 ^是一个特殊字符,使用时必须用双引号引起来才能正确运行 git reset -hard HEAD”^” 或者 git reset -hard”HEAD^”

这样一来最新的版本已经看不到了,但只要命令窗口还为关闭,只要能找到需要回到最新的版本号的commit id,于是就可以回到未来的某个版本。

git reset –hard 3628164 —–>在这里版本号不需要写全 Git会自己匹配查找

但如果你命令窗口关闭了,或者到了第二天需要返回到曾经的最新版本,则必须要找到当时版本的commit id。在git中提供了一个gitreflog命令来记录你的每一次命令。

小结

l HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset –hard commit_id。

l 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。

l 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

Git的工作区和暂存区

工作区(WorkingDirectory)

就是本地电脑可以看到的目录


版本库(Repository)



工作区中有一个隐藏的目录 .git,这个不算工作区,而是Git的版本库。

Git的版本库中存放了很多东西,其中最重要的就是成为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

文件往Git版本库中添加的时候,是分两步执行的:

第一步是: git add把文件添加进去,实际上就是把文件修改添加到暂存区。

第二步是: git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以 git commit就是往master分支上提交修改。

管理修改

Git跟踪并管理的是修改,而非文件。

第一次修改 -> git add -> 第二次修改 -> git commit

由于Git管理的是修改,当你使用git add命令后,在工作区的第一次修改会被放入暂存区,但是第二次修改的并没有放在暂存区,所以git commit提交的是第一次修改的版本。

提交后,用git diff HEAD – 命令可以查看工作区和版本库里面最新版本的区别。

撤销修改

Git中使用 git checkout -- < filename> 丢掉工作区的所有修改。


命令git checkout – 的意思是,把文件在工作区的所有修改撤销,这里有两种情况:

一种是:文件自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

一种是:文件已经添加到暂存区后,又作了修改,现在撤销修改就回到添加到暂存区后的状态。

总之,就是让这个文件回到最近的一次 git commit 或 git add 时的状态。

Git中使用gitreset HEAD <filename>命令可以将暂存区的修改撤销,重新放回工作区。
git reset 命令既可以回退版本,也可以将暂存区的修改退回到工作区。当我们用HEAD时,表示最新版。


小结

场景一:当你乱改了工作区的某个文件的内容,想直接丢弃工作区的时,用命令gitcheckout –

场景二:当你不但乱改了工作区的某个文件的内容,还添加到了暂存区,想丢弃修改,分两步,首先使用命令gitreset HEAD ,就回到了场景一,第二部按场景一操作。

场景三:已经提交了不合适的修改到了版本库时,想要撤回本次提交,可以采用版本回退(git reset –hard HEAD^)回退到上一个版本,不过前提是没有推送到远程库。

删除文件

一般情况下,通常可以直接将在文件管理器中把没用的文件删除了,或者使用rm命令删掉:rm<filename>
如果确实要将文件从版本库中删除,那就使用命令git rm删掉,并且git commit.
如果删错了,因为版本库中还有这个文件,所以可以使用命令 git checkout -- <filename>将误删的文件恢复到最新版本。


远程仓库

Git是一个分布式版本控制系统,同一个Git仓库,可以分布在不同的机器上。最早,只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。
然而,现阶段还没有必要自己搭建Git服务器,可以直接使用GitHub来作为Git服务器仓库。
由于本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以需要进行一下的设置。
第1步:创建SSH Key,在用户主目录下,看看有没有.ssh目录和这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"


你需要把邮件地址换成你自己的邮件地址(其实就是公钥的名字),然后一路回车,使用默认值即可。也可以直接ssh-keygen

之后在用户目录下就可以找到 .ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的密钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥。

第2步:登陆GitHub,打开Account settings,SSH Keys界面。然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:

点“Add Key”,你就应该看到已经添加的Key。

替换密钥时需要将原来的.ssh文件夹删掉并重新生成即可。

添加远程库

目标:在GitHub新建一个Git仓库,让两个仓库进行远程同步。

首先在GitHub上新建一个Git仓库。然后在本地的Git仓库运行:
gitremote add origin git@github.com:<GitHub用户名>/<新建的GitHub仓库名.git>


这里面 origin是远程库的名称,是Git的默认叫法,也可以进行修改。

下一步,就可以把本地库的所以内容推送到远程库上:

gitpush -u origin master

把本地库的内容推送到远程,使用git push命令,实际上是把当前分支master推送到远程。

由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

从现在起,只要本地做了提交,就可以通过命令:git pushorigin master 把本地的master分支的最新修改推送到GitHub。

小结

要关联一个远程库使用命令gitremote add origin git@server-name:path/repo-name.git

关联后使用命令 git push -u origin master 第一次推送master分支的所有内容。

此后每次版本更新只需要使用命令 git push origin master 推送最新的修改。

从远程库克隆

上次我们讲了先有本地库,后有远程库的时候,如何关联远程库。现在,我们从零开始,先创建远程库,然后,从远程库克隆。

首先,登陆GitHub,创建一个新的仓库,名字叫gitskills

然后选择Initialize this repositorywith a README,这样GitHub会自动为我们创建一个README.md文件。

现在我们使用命令远程克隆一个本地库:

git clone git@github.com:

小结

要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。

Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。

分支管理

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能使用。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

创建与合并分支

在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。


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



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

当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:



Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化。

不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变。



假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并。



所以Git合并分支也很快,只是改改指针,工作区内容也不变。

合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:



实战:

首先我们创建 dev 分支,然后切换到 dev 分支。

gitcheckout -b dev

git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

git branch dev

gitcheckout dev

然后,用git branch命令查看当前分支:

git branch

git branch命令会列出所有分支,当前分支前面会标一个*号。

然后我们就可以在dev分支上正常提交。等到,dev分支工作完成时,我们就可以切回master分支。

gitcheckout master

切换回master分支后,再查看之前在dev分支提交的文件,会发现才添加的内容还没有出现,那时因为那个提交是在dev分支上,而master分支此刻的提交点并没有变。

所以现在,我们要把dev分支的工作成果合并到master分支上:



git merge dev

git merge命令用于合并指定分支到当前分支。合并后,再查看文件内容,就可以看到,和dev分支的最新提交是完全一样的。

合并完成后,我们就可以删除dev分支了:

git branch -d dev

删除后,查看branch,就只剩下master分支了:

git branch

小结

Git鼓励大量使用分支:

查看分支:git branch

创建分支:git branch

切换分支:git checkout

创建+切换分支:git checkout -b

合并某分支到当前分支:git merge

删除分支:git branch -d

解决冲突

准备新的feature1分支,继续我们的新分支开发:

$ gitcheckout -b feature1

Switched to a new branch’feature1’

修改readme.txt最后一行,改为:

Creating a new branch isquick AND simple.

在feature1分支上提交:

$ git add readme.txt

$ git commit -m “AND simple”

[feature1 75a857c] AND simple

1 file changed, 1 insertion(+), 1 deletion(-)

切换到master分支:

$ git checkout master

Switched to branch ‘master’

Your branch is ahead of’origin/master’ by 1 commit.

Git还会自动提示我们当前master分支比远程的master分支要超前1个提交。

在master分支上把readme.txt文件的最后一行改为:

Creating a new branch is quick & simple.

提交:

$ gitadd readme.txt

$ gitcommit -m “& simple”

[master 400b400] & simple

1 file changed, 1 insertion(+), 1 deletion(-)

现在,master分支和feature1分支各自都分别有新的提交,变成了这样:



这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:

$ git merge feature1

Auto-merging readme.txt

CONFLICT (content): Mergeconflict in readme.txt

Automatic merge failed; fixconflicts and then commit the result.

果然冲突了!Git告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。git status也可以告诉我们冲突的文件:

$ git status

On branch master

no changes added to commit (use “gitadd” and/or “git commit -a”)

我们可以直接查看readme.txt的内容:

Git is a distributed versioncontrol system.

Git is free softwaredistributed under the GPL.

Git has a mutable indexcalled stage.

Git tracks changes of files.

<<<<<<< HEAD

Creating a new branch isquick & simple.

Creating a new branch isquick AND simple.

>>>>>> feature1

Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:

Creating a new branch is quick and simple.

再提交:

$ git add readme.txt

$ git commit -m “conflict fixed”

现在,master分支和feature1分支变成了下图所示:

用带参数的git log也可以看到分支的合并情况:

$ git log –graph –pretty=oneline–abbrev-commit

* 59bc1cb conflict fixed

|\

| *75a857c AND simple

* |400b400 & simple

|/

*fec145a branch test



最后,删除feature1分支:

$ git branch -d feature1

工作完成。

小结

当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

用git log –graph命令可以看到分支合并图。

分支管理策略

通常合并分支的时,Git一般会Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。如果强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支的历史就可以看出分支的信息。
下面我们使用--no-ff方式的git merge:


首先,仍然创建并切换dev分支:

git checkout -b dev

修改readme.txt文件,并提交一个新的commit:

git add readme.txt

git commit -m “addmerge”

现在,我们切换回master:

git checkout master

准备合并dev分支,请注意–no-ff参数,表示禁用Fast forward:

git merge –no-ff -m”merge with no-ff” dev

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。合并后,我们用git log看看分支历史:

git log –graph–pretty=oneline –abbrev-commit

可以看到,不使用Fast forward模式,merge后就像这样:

分支策略

在实际开发中,我们应该按照几个基本原则进行分支管理:首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。所以,团队合作的分支看起来就像这样:

小结

Git分支十分强大,在团队开发中应该充分应用。合并分支时,加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。

Bug分支

在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
Git提供了一个stash功能,可以把当前工作现场存储起来,等以后恢复现场后继续工作:       git stash


首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:

git checkout master

git checkout -b issue-101

现在修复bug,然后提交:

git add readme.txt

git commit -m “fix bug101”

修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:

git checkout master

git merge –no-ff -m”merged bug fix 101” issue-101

git branch -d issue-101

接着回到dev分支

git checkout dev

git status

工作区是干净的,用git stash list命令查看刚才的工作现场存到哪了。

git stash list

工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;

另一种方式是用git stash pop,恢复的同时把stash内容也删了:

git stash pop

再用git stash list查看,就看不到任何stash内容了:

git stash list

你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

git stash apply stash@{0}

小结

修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。

Feature分支

添加一个新功能时,为了不把主分支搞乱了,所以最好建一个feature分支,在上面开发,完成后合并,最后,删除该feature分支。


git checkout -b feature-new —创建了一个名字是feature-new的分支

开发完毕后:

git add new.py

git status

git commit -m “add feature new”

切回dev,准备合并:

git checkout dev

将feature分支和bug分支合并,然后删除。

但如果,由于一些原因,新功能被取消,所以这个分支必须就地销毁。

git branch -d feature-new 但由于分支还没有合并,所以这样销毁会失败,如果强行删除,需要使用命令gitbranch -D feature-new

小结

开发一个新feature,最好新建一个分支。如果要丢弃一个没有被合并的分支,可以通过git branch -D 强行删除。

多人协作

当你从远程仓库克隆时,实际上Git自动的把本地的master分支和远程的master对应起来了,并且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote,或者使用git remote -v显示更详细的信息。git remote -v显示了抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。


推送分支

推送分支,就是把该分支推送到远程库。推送时要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上。

git push origin master

如果要推送其他分支,如dev就要改成 git push origin dev

但是,并不一定要把本地分支往远程分支推送。

master分支是主分支,因此要时刻与远程同步;

dev分支是开发分支,团队所有成员都要在上面工作,所以也需要与远程同步。

bug分支只用于在本地修复bug,所以就没必要推到远程了。

feature是否推送到远程,取决于你是否要和小伙伴合作在上面开发。

总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视心情而定!

抓取分支

多人协作时,大家都会往master和dev分支上推送各自的修改。
但现在一个小伙伴从远程clone时,默认情况下只能看到你本地的master分支。现在,你的小伙伴要在dev分支上开发,就必须创建远程origin和dev分支到本地,于是用


git checkout -b dev origin/dev

现在,他就可以在dev上继续修改,然后时不时把dev分支push到远程。

git clone git@github.com:tomatoyan/learngit.git

git config user.name “Bob”

git config user.email “bob@example.com”

git branch

git checkout -b dev origin/dev

git add hello.py

git commit -m “add hello info”

git push origin dev

如果你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送:

$ git add hello.py

$ git commit -m “add coding: utf-8”

[dev bd6ae48] add coding: utf-8

1 filechanged, 1 insertion(+)

$ git push origin dev

To git@github.com:michaelliao/learngit.git

![rejected] dev -> dev(non-fast-forward)

error: failed to push some refs to ‘git@github.com:michaelliao/learngit.git’

hint: Updates were rejected because the tip ofyour current branch is behind

hint: its remote counterpart. Merge the remotechanges (e.g. ‘git pull’)

hint: before pushing again.

hint: See the ‘Note about fast-forwards’ in’git push –help’ for details.

推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,Git已经提示我们,先用git pull把最新的提交origin/dev抓下来,然后,在本地仓库,解决冲突,再推送。

$ git pull

remote: Counting objects: 5, done.

remote: Compressing objects: 100% (2/2), done.

remote: Total 3 (delta 0), reused 3 (delta 0)

Unpacking objects: 100% (3/3), done.

From github.com:michaelliao/learngit

fc38031..291bea8 dev -> origin/dev

There is no tracking information for thecurrent branch.

Please specify which branch you want to mergewith.

See git-pull(1) for details

gitpull

If you wish to set tracking information forthis branch you can do so with:

gitbranch –set-upstream dev origin/

git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接。

$ git branch –set-upstream dev origin/dev

Branch dev set up to track remote branch dev from origin.

再pull:

$ git pull

Auto-merging hello.py

CONFLICT (content): Merge conflict in hello.py

Automatic merge failed; fix conflicts and then commit the result.

这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:

$ git commit -m “merge & fix hello.py”

[dev adca45d] merge & fix hello.py

$ git push origin dev

Counting objects: 10, done.

Delta compression using up to 4 threads.

Compressing objects: 100% (5/5), done.

Writing objects: 100% (6/6), 747 bytes, done.

Total 6 (delta 0), reused 0 (delta 0)

To git@github.com:michaelliao/learngit.git

291bea8..adca45d dev -> dev

因此,多人协作的工作模式是这样:

1、 首先,可以试图用git push origin 推送自己的修改;

2、 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;

3、 如果合并有冲突,则解决冲突,并在本地提交;

4、 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功。

如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch –set-upstreambranch-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,如果有冲突,要先处理冲突。


查看历史分支流程提交信息 git log –graph –pretty=oneline –abbrev-commit

标签管理

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

Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针,所以,创建和删除标签都是瞬间完成的。

Git有commit,为什么还要引入tag?

“请把上周一的那个版本打包发布,commit号是6a5819e…”

“一串乱七八糟的数字不好找!”

如果换一个办法:

“请把上周一的那个版本打包发布,版本号是v1.2”

“好的,按照tag v1.2查找commit就行!”

所以,tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。

创建标签

在Git中打标签很简单,首先,切换到需要打标签的分支上。
git tag <name>就可以打一个新标签:git tagv1.0
然后可以用命令git tag查看所有的标签。


默认的标签是打在最新提交的commit上的,有时候,如果忘了打标签,方法是找到历史提交commit id,然后打上就好了。

git log –pretty=oneline–abbrev-commit

要对add merge的这次提交加标签,它对应的commit id是6224937,则敲入

git tag v1.0 6224937

这里的标签不是按照时间顺序列出,而是按照字母排序的。可以用git show查看标签信息。

还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字。

git tag -a -m <”说明文字”>

还可以通过-s用私钥签名一个标签:

git tag -s -m <”说明文字”>

签名采用PGP签名,因此,必须首先安装gpg(GnuPG),如果没有找到gpg,或者没有gpg密钥对,就会报错。

用命令git show 可以看到PGP签名信息:

小结

命令git tag <name>用于新建一个标签,默认为HEAD,也可以指定一个commit id


git tag -a -m <“说明文字”>可以指定标签信息

git tag -s -m <“说明文字”>可以用PGP签名标签

命令git tag可以查看所有标签

操作标签

标签的删除:git tag -d v0.1

git tag -d

推送标签去远程

git push origin

或者一次性推送全部尚未推送到远程的本地标签:

git push origin –tags

但如果标签推送到了远程,要删除就麻烦一点了,先从本地删除:

git tag -d

然后,再从远程删除。删除命令也是push,格式如下:

git push origin:refs/tags/

小结

l 命令git push origin 可以推送一个本地标签;

l 命令git push origin –tags 可以推送全部未推送过的本地标签;

l 命令git tag -d 可以删除一个本地标签;

l 命令git push origin :refs/tags/ 可以删除一个远程标签。

使用GitHub

如何参与GitHub上的开源项目。


git clone git@github.com:michaelliao/boostrap.git

一定要从自己的帐号下clone仓库,这样才能推送修改。如果从boostrap的作者的仓库地址git@github.com:twbs/boostrap.git克隆,因为没有权限,你将不能修改推送。

如果你想修复boostrap的一个bug,或者新增一个功能,立刻就可以开始干活,干完后就可以往自己的仓库推送。

如果你希望boostrap的官方库能接受你的修改,你就可以在GitHub上发起一个pull request。当然,对方是否接受你的pull request就不一定了。

小结

l 在GitHub上,可以任意Fork开源仓库;

l 自己拥有Fork后的仓库的读写权限;

l 可以推送pull request给官方仓库来贡献代码。

自定义Git

我们可以配置user.name和user.email。

我们可以让Git显示颜色

git config –globalcolor.ui true

这样Git会适当地显示不同的颜色。

忽略特殊文件

在Git工作区的根目录下创建一个特殊的 .gitignore文件,然后把要忽略的文件名添加进去,Git就会自动忽略这些文件。不要从头写 .gitignore文件,GitHub已经准备为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore


忽略文件的原则是:

1.忽略操作系统自动生成的文件,比如缩略图等;

2.忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;

3.忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

最后一步就是把 .gitignore也提交到Git。

当然检验.gitignore的标准是git status命令是不是说working directory clean。

使用Windows时,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:

$ git add App.class

The following paths areignored by one of your .gitignore files:

App.class

Use -f if you really want toadd them.

如果你确实想添加该文件,可以用-f强制添加到Git:

$ git add -f App.class

或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用gitcheck-ignore命令检查:

$ git check-ignore -v App.class

.gitignore:3:*.class App.class

Git会告诉我们,.gitignore的第3行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。

小结

l 忽略那些文件,需要编写 .gitignore;

l .gitignore文件本身要放到版本库里,并且可以对 .gitignore做版本管理。

配置别名

我们可以对命令配置成别名

比如可以用git st就表示git status

我们只需敲一行命令,告诉Git,以后st就表示 status

git config –globalalias.st status

当然还有别的命令可以简写,很多人都用co表示checkout,ci表示commit,br表示branch:

$ git config –globalalias.co checkout

$ git config –globalalias.ci commit

$ git config –globalalias.br branch

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

配置文件

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

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

$ cat .git/config

[core]

repositoryformatversion = 0

filemode = true

bare = false

logallrefupdates = true

ignorecase = true

precomposeunicode = true

[remote “origin”]

url = git@github.com:tomato/learngit.git

fetch = +refs/heads/:refs/remotes/origin/

[branch “master”]

remote = origin

merge = refs/heads/master

[alias]

last = log -1

别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。

而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:

$ cat .gitconfig

[alias]

co = checkout

ci = commit

br = branch

st = status

[user]

name = Your Name

email = your@email.com

配置别名也可以直接修改这个文件,如果改错了,可以删掉文件重新通过命令配置。

搭建Git服务器

搭建Git服务器需要准备一台运行Linux的机器,强烈推荐用Ubuntu或Debian,这样,通过几条简单的apt命令就可以完成安装。
假设你已经有sudo权限的用户账号,下面,正式开始安装。


第一步,安装git:

sudo apt-get install git

第二步,创建一个git用户,来运行git服务:

sudo adduser git

第三步,创建证书登录:

收集所有需要登录的用户的公钥,就是他们自己的id_rsa.pub文件,把所有公钥导入到/home/git/.ssh/authorized_keys文件里,一行一个。

第四步,初始化Git仓库:

先选定一个目录作为一个Git仓库,假定是 /srv/sample.git ,在 /srv 目录下输入命令:

sudo git init–bare sample.git

Git就会创建一个裸仓库,裸仓库没有工作区,因为服务器上的Git仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的Git仓库通常都以.git结尾。然后,把owner改为git:

sudo chown -R git:gitsample.git

第五步,禁用shell登录,出于安全考虑,第二件创建的git用户不允许登录shell,这可以通过编辑 /etc/passwd 文件完成。找到类似下面的一行:

git:x:1001:1001:,,,:/home/git:/bin/bash

改为:

git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

这样,git用户可以通过ssh使用git,但无法登录shell,因为我们为git用户指定的git-shell每一次登陆就自动退出。

第六步,克隆远程仓库。现在可以通过git clone命令克隆远程仓库,在各自的电脑上运行。

gitclone git@server:/srv/sample.git

剩下的便是推送了。

管理公钥

如果团队很小,把每个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys文件里就是可行的。如果团队有几百号人,就没法这么玩了,这时,可以用Gitosis来管理公钥。这里我们不介绍怎么玩Gitosis了,几百号人的团队基本都在500强了,相信找个高水平的Linux管理员问题不大。


管理权限

有很多不但视源代码如生命,而且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每个人是否有读写权限会精确到每个分支甚至每个目录下。因为Git是为Linux源代码托管而开发的,所以Git也继承了开源社区的精神,不支持权限控制。不过,因为Git支持钩子(hook),所以,可以在服务器端编写一系列脚本来控制提交等操作,达到权限控制的目的。Gitolite就是这个工具。这里我们也不介绍Gitolite了,不要把有限的生命浪费到权限斗争中。


小结

搭建Git服务器非常简单,通常10分钟即可完成;要方便管理公钥,用Gitosis;要像SVN那样变态地控制权限,用Gitolite。

参考文献:

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

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

https://git-scm.com/book/zh/v2
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  git