Git使用教程

来源:互联网 发布:大数据用什么语言最好 编辑:程序博客网 时间:2024/06/05 10:41

本文同步发布于我的个人网站:Git教程


前言

Git是一款免费、开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。本文为廖雪峰的Git教程的个人笔记,欢迎指正。


1 Git基础

1.1 版本控制系统

版本控制系统系统分为集中式分布式两种。

集中式是集中存放在中央服务器中,工作的时候,先用自己的电脑从中央服务器取得最新的版本,完工后,再把自己的工作推送到中央服务器。集中式版本控制工具有:CVS、SVN等。

集中式的特点是需要联网才能工作,对网速的要求较高。如果中央服务器发生了宕机,所有人都没法工作。

集中式

分布式版本控制系统没有“中央服务器”,每个人的电脑上都是一个完整的版本库,工作的时候不需要联网。需要彼此的文件,只需要相互推送。实际使用中,分布式版本控制控制系统通常也有一台充当“中央服务器”的电脑,但仅仅是用来方便“交换”大家的修改,没有它大家一样能正常工作,只是交换修改不方便。分布式版本控制工具有:Git、Mercurial、Bazaar等。

分布式的特点是不需要联网就能工作。不依赖中央服务器,安全性高。

分布式

1.2 安装Git

测试是否正确安装了Git

Git测试安装

如果像上图这样显示没有安装,通过相应包管理直接安装即可。我的电脑为CentOs,因此键入命令

yum install git

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

$ git config --global user.name "Your Name"$ git config --global user.email "email@example.com"

因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址。

注意:git config命令的--global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址。

自报家门

1.3 工作区和暂存区

Git和其他版本控制系统如SVN有一个不同之处就是有暂存区的概念。首先我们先了解以下概念的意义。

工作区(Working Directory)

就是你在电脑里能看到的目录,比如learngit文件夹就是一个工作区:

工作区

版本库(Repository)

版本库可以理解为一个目录,在目录中的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,一边任何时刻都可以追踪历史,或者在将来进行还原。

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

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

版本库

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

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

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

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

你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改

1.4 三个具有代表性的命令

  1. 添加到版本库:git add

  2. 提交到版本库:git commit

  3. 把本地版本库推送到远程版本库:git push

三大命令


2 版本控制

2.1 创建版本库

  1. 选择合适路径,创建一个空目录

  2. 使用git init初始化git管理的目录

创建版本库

然后我们添加文件到版本库

  1. 编辑文本文件readme.txt

  2. 添加到版本库:git add

  3. 提交到版本库:git commit

注1: commit 命令使用-m参数可以添加本次提交的注释。这非常有用,在团队合作中能够让别人理解你本次提交的修改内容。

注2:我们可以用git add添加多个文件到暂存区,然后使用git commit一次性提交。

提交文件

2.2 查看仓库状态

git status查看当前仓库状态

修改readme.txt文件,使用git status查看仓库状态,下图说明readme.txt文件被修改,但还没有提交到仓库。

查看仓库状态

git diff查看修改的内容

下图说明readme.txt,添加了一行内容。

查看修改

将readme.txt添加到暂存区并提交后,再次使用git statusgit diff查看。

查看修改2

git log查看仓库历史纪录

git log命令显示从最近到最远的提交日志。

查看历史纪录

2.3 版本回退

git reset回退到指定版本

git reset具有三个参数,分别是softhardmixed

--soft参数告诉Git重置HEAD到另外一个commit,但也到此为止。如果你指定–soft参数,Git将停止在那里而什么也不会根本变化。这意味着index,working copy都不会做任何变化,所有的在original HEAD和你重置到的那个commit之间的所有变更集仍然在stage(index)区域中。

soft

--hard参数将会将重置HEAD返回到另外一个commit(取决于~12的参数),重置index以便反映HEAD的变化,并且重置working copy也使得其完全匹配起来。这是一个比较危险的动作,具有破坏性,数据因此可能会丢失!如果真是发生了数据丢失又希望找回来,那么只有使用git reflog命令了。

hard

--mixed是reset的默认参数,也就是当你不指定任何参数时的参数。它将重置HEAD到另外一个commit,并且重置index以便和HEAD比配,但是也到此为止。working copy不会被更改。所以所有从original HEAD到你重置到的那个commit之间的所有变更仍然保存在working copy中,被标示为已变更,但是并未staged的状态。

mixed

Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上个版本就是HEAD^^。往上N个版本可以写为HEAD~N,如上100个版本为HEAD~100。

撤销后再查看记录发现提交记录少了一个

版本撤销

也可以指定回滚的版本号。版本号用git log查看commit id前7位。

如果我们忘记回退前的版本号,git reflog命令记录了每一次的命令操作,包含了所有版本的版本号。

查看操作记录

2.4 撤销修改

git checkout - - file

该命令会把文件在工作区的修改全部撤销,回到最近一次git commitgit add时的状态。

  • 文件自修改后还没有被放到暂存区,撤销修改就回到和版本库一模一样的状态
  • 文件已经添加到了暂存区后。又做了修改,撤销修改就回到添加到暂存区后的状态。

注:--请不要丢掉,丢掉后就成为了创建分支的命令。

撤销修改

git reset HEAD file

该命令会把暂存区的修改撤销掉,重新放回工作区中。

我们之前在回退版本时已经介绍了git reset命令,该命令既可以回退版本,也可以把工作区的某些文件替换为版本库中的文件。使用HEAD表示为最新的版本。

2.5 删除文件

git rm file

如果使用rm删除了版本库中的文件test.txt,然后用git status查看仓库状态。

查看删除文件

如果确实要将test.txt文件从Git仓库删除,使用git rm,并commit。

git中删除

提交删除

如果误删,使用git checkout -- file恢复到之前版本。

误删文件

2.6 命令小节

版本控制命令小节


3 远程仓库

远程仓库即远程的Git服务器仓库,每个用户都能从这个服务器仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库中,也可以从服务器仓库中获取别人的提交。

3.1 创建和设置远程仓库

我们可以使用自己的服务器创建一个Git仓库,也可以使用GitHub为我们提供的仓库。这里使用GitHub,首先注册GitHub账号。

GitHub需要识别推送者的身份,防止别人冒充。Git支持SSH协议,因此GitHub只要知道了你的公钥,就可以确认推送者的身份。GitHub允许添加多个Key,确保用户可以在多台电脑上进行推送。

需要注意的是,GitHub只免费提供公开的Git库,因此你提交的内容所有人都可以查看,因此敏感信息尽量不要出现。如果不想让别人看到,可以选择GitHub付费服务或者自己搭建Git服务器。

首先创建SSH Key密钥。一路回车使用默认值即可(如果没有特殊需求无需设置密码)。

创建密钥

然后可以在用户主目录里找到.ssh目录,里面有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。

复制~/.ssh/id_rsa.pub内容。

查看公钥

第二步,登陆GitHub,打开Settings –>SSH And GPL Keys–>New SSH key–> Add SSH key,将之前的内容粘贴上去即可。

添加Key

3.2 添加远程库

首先登陆自己的GitHub,创建一个新的仓库,这里我设置仓库名为Test。

创建仓库

GitHub告诉我们有以下几种选择:

  • 从这个仓库克隆出新的仓库

  • 把一个已有的本地仓库与之关联

  • 从其他仓库导入代码。

根据提示,我们把本地仓库的内容推送到GitHub仓库。在本地仓库下,执行GitHub提示我们的命令即可。

关联仓库

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

我们发现上图中出现了Warning,这是因为当你第一次使用Git的clone或者push命令连接GitHub时,由于我们使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。

Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了,这个警告只会出现一次,后面的操作就不会有任何警告了。

3.3 从远程库克隆

这里用我已经存在的OJCrawler项目为例,用命令git clone将该项目克隆到本地。

git clone git@github.com:jitwxs/OJCrawler.git

克隆仓库到本地

3.4 命令小节

远程控制命令小节


4 分支管理

分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN。

如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git又学会了SVN!

分支漫画

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

其他版本控制系统如SVN等都有分支管理,但是用过之后你会发现,这些版本控制系统创建和切换分支比蜗牛还慢,简直让人无法忍受,结果分支功能成了摆设,大家都不去用。

但Git的分支是与众不同的,得益于它的数据结构,使得无论创建、切换和删除分支,Git在很短时间就能完成。

4.1 创建与合并分支

Git将每次提交的内容串成一条时间线,这条时间线就是一个分支。在默认情况下只有一个分支,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。

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

master分支

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

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

新建dev分支

由这个数据结构我们知道,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!

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

修改dev分支

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

合并分支

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

删除分支

说了这么多理论,下面开始实际操作。

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

git checkout -b dev

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

git branch devgit checkout dev

然后,用git branch命令查看分支,当前活跃分支前会添加*号:

查看分支

下面我们为readme.txt文件添加一行,并提交dev分支。

在dev分支修改内容

切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!

切换回master

因为那个提交是在dev分支上,而master分支此刻的提交点并没有变。

切换回状态图

现在,我们把dev分支的工作成果合并到master分支上,git merge命令用于合并指定分支到当前分支。

合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

合并dev分支

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

合并完成后,就可以放心地删除dev分支了 使用git branch -d 分支名

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

删除dev分支

因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

4.2 解决冲突

合并分支并非总是这么一帆风顺,有可能遇上冲突问题。

准备新的feature1分支,来模拟冲突问题。

创建feature1分支

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

this changed by feature1 branch..

在feature1分支上提交:

提交feature1

切换到master分支:

切换master

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

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

this changed by master branch..

提交:

提交master

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

冲突图

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

尝试合并冲突

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

git status也可以告诉我们冲突的文件:

git status冲突

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

查看冲突内容

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

this changed by master and dev branch..

再提交:

查看合并

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

合并示意

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

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

git log冲突

最后,删除feature1分支:

删除feature1

4.3 分支管理策略

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

我们可以强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

下面我们实战一下non-fast-forward方式的merge。

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

创建dev分支

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

提交dev分支

现在,我们切换回master:

切换到master

准备合并dev分支,请注意–no-ff参数,表示禁用Fast forward。因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

noff合并分支

合并后,我们用git log看看分支历史:

git log历史

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

noff原理

在实际开发中,我们应该按照几个基本原则进行分支管理:

首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活,干活都在dev分支上。

也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

所以,团队合作的分支看起来就像这样:

分支策略

4.4 Bug分支

当你接到一个修复bug的任务时,很自然地,你想创建一个分支来修复它。但是等等,当前分支上进行的工作还没有提交。并不是你不想提交,而是工作只进行到一半,还没法提交。如下图,demo.c文件还没有完成,无法提交。

无法提交演示

但是,你必须紧急修复该bug,怎么办?幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作。

stash

现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。

查看隐藏后status

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

创建issue分支

现在模拟修复bug,随便修改readme.txt内容,然后提交:

提交issue分支

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

删除issue

修复完了Bug,是时候接着回到dev分支干活了!

返回dev

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

查看stash

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

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

  • git stash pop,恢复的同时把stash内容也删了。

这里假设我们不需要保留stash的内容了,使用git stash pop命令。再用git stash list查看,就看不到任何stash内容了:

stash pop

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

git stash apply stash@{0}

4.5 多人协作

你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。

git remote查看远程库的信息,或者,用git remote -v显示更详细的信息:

git remote

上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。

多人协作时,大家都会往master和dev分支上推送各自的修改。

当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。

现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用git checkout -b dev origin/dev创建本地dev分支:

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

碰巧你也对同样的文件作了修改,并试图推送就会出错失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,先用git pull把最新的提交从origin/dev克隆下来,然后,在本地合并,解决冲突,再推送:

以上就是多人协作的工作模式,下面来总结一下:

  • 首先,可以试图用git push origin branch-name推送自己的修改;

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

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

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

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

4.6 命令小节

分支命令


5 标签管理

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

Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(与分支很像但是分支可以移动,标签不能移动)。

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

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

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

如果换一个办法:

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

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

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

5.1 创建标签

在Git中打标签非常简单,首先,切换到需要打标签的分支上,然后,敲命令git tag <name>就可以打一个新标签:

打标签

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

查看标签

默认标签是打在最新提交的commit上的。如果想要给历史commit打标签,可以找到历史提交的commit id,然后打上就可以了:

查看git log

比方说要对add merge这次提交打标签,它对应的commit id是3728b64,敲入命令git tag v0.1 6224937

再用命令git tag查看标签:

查看标签2

注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>查看标签信息:

查看标签具体

可以看到,v0.1确实打在add merge这次提交上。

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

git tag -a v0.1 -m "version 0.1 released" 3628164

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

$ git tag -s v0.2 -m "signed version 0.2 released" fec145a

签名采用PGP签名,因此,必须首先安装gpg(GnuPG),用PGP签名的标签是不可伪造的,因为可以验证PGP签名。

5.2 操作标签

如果标签打错了,也可以删除:

git tag -d v0.1

删除标签

因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。

如果要推送某个标签到远程,使用命令git push origin <tagname>,或者,使用git push origin --tags一次性推送全部尚未推送到远程的本地标签。

推送标签

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

git tag -d v0.1

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

git push origin :refs/tags/v0.1

要看看是否真的从远程库删除了标签,可以登陆GitHub查看。

5.3 命令小节

标签命令


6 自定义Git

6.1 搭建Git服务器

6.1.1 搭建环境

GitHub就是一个免费托管开源代码的远程仓库。但是对于某些视源代码如生命的商业公司来说,既不想公开源代码,又舍不得给GitHub交保护费,那就只能自己搭建一台Git服务器作为私有仓库使用。

搭建Git服务器需要准备一台运行Linux的机器或服务器。

假设你已经有sudo权限的用户账号,下面,正式开始安装。

第一步,安装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:git sample.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命令克隆远程仓库了,在各自的电脑上运行:

git clone git@server:/srv/sample.git

剩下的推送就简单了。

6.1.2 管理公钥

如果团队很小,把每个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys文件里就是可行的。如果团队有几百号人,可以用Gitosis来管理公钥。

6.2 设置忽略文件

有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files ...

好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore 。

忽略文件的原则是:

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

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

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

举个例子:

假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:

# Windows:Thumbs.dbehthumbs.dbDesktop.ini

然后,继续忽略Python编译产生的.pyc、.pyo、dist等文件或目录:

# Python:*.py[cod]*.so*.egg*.egg-infodistbuild

加上你自己定义的文件,最终得到一个完整的.gitignore文件,内容如下:

# Windows:Thumbs.dbehthumbs.dbDesktop.ini# Python:*.py[cod]*.so*.egg*.egg-infodistbuild# My configurations:db.inideploy_key_rsa

最后一步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status命令是不是说working directory clean

使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。

有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:

$ git add App.classThe following paths are ignored by one of your .gitignore files:App.classUse -f if you really want to add them.

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

$ git add -f App.class

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

$ git check-ignore -v App.class.gitignore:3:*.class    App.class

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


7 Git进阶

7.1 修改已经被覆盖的提交

如果你不想看详细的描述,直接看步骤即可:

1.git rebase -i HEAD~n,将要修改的提交状态改为edit

2.修改文件

3.git add

4.git commit --amend

5.git rebase --continue

假设我们目录下有三个文件,分别是digit.datletter.datsymbol.datdigit.dat中存放着数字,letter.dat中存放着字母,symbol.dat中存放着符号。

我们先提交digit.dat,然后提交letter.dat,最后提交symbol.dat:

此时我们想起来,letter.dat中仅仅存放了小写字母,大写字母被遗忘了,我们要把大写字母补充进去。这时候有两种解决方法:

  • 修改letter.dat内容,并发起一次新提交

  • 不发起新提交,对之前的那次提交做修改

我们不讨论发起新提交的情况,仅仅讨论如何对那次提交做修改。你也许会说,这很简单啊,直接使用命令reset HEAD^或者reset 8cc5dc不就好了吗?

不错,这没有问题,但是这样的话我们对symbol.dat的那次提交也被撤回了,这显然是一个笨方法,特别是当你要修改的那次提交被覆盖的很深的情况下。

有没有在不影响其他的提交的情况下,对已经被覆盖的提交做修改的方法呢?答案是有的。

Step1 : git rebase -i HEAD~n

我们使用命令git rebase -i HEAD~2列出最新的两次提交:

git rebased命令的交互命令中,首先逆序存放了我们最新的两次提交,最前面的状态为pick。下面也提示了我们可以执行哪些命令,这里我们这里只使用它的edit功能。

将我们要修改的那次提交状态改为edite,也就是将第一行内容改为:

edit 8cc5dcb add letter.dat

然后保存退出:

git已经提示我们此时已经暂停在了8cc5dc这一次提交上,后面新的提交此时应该被隐藏掉了,查看日志验证我们的判断:

不出所料,添加symbol.dat的那次提交已经被隐藏掉了,添加letter.dat的那次提交已经成为当前最新的提交了,这时候我们就可以轻松对它进行操作了。

Step2 : 修改文件内容

Step3 : git addgit commit --amend

其实之前的图上已经提示我们如何操作了,先git add,然后执行命令git commit --amend提交变更。

Step4 : git rebase --continue

此时就已经完成了对那次提交的修改,查看日志和文件内容,大功告成。

原创粉丝点击