Git使用教程
来源:互联网 发布:大数据用什么语言最好 编辑:程序博客网 时间:2024/06/05 10:41
本文同步发布于我的个人网站:Git教程
前言
Git是一款免费、开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。本文为廖雪峰的Git教程的个人笔记,欢迎指正。
1 Git基础
1.1 版本控制系统
版本控制系统系统分为集中式和分布式两种。
集中式是集中存放在中央服务器中,工作的时候,先用自己的电脑从中央服务器取得最新的版本,完工后,再把自己的工作推送到中央服务器。集中式版本控制工具有:CVS、SVN等。
集中式的特点是需要联网才能工作,对网速的要求较高。如果中央服务器发生了宕机,所有人都没法工作。
分布式版本控制系统没有“中央服务器”,每个人的电脑上都是一个完整的版本库,工作的时候不需要联网。需要彼此的文件,只需要相互推送。实际使用中,分布式版本控制控制系统通常也有一台充当“中央服务器”的电脑,但仅仅是用来方便“交换”大家的修改,没有它大家一样能正常工作,只是交换修改不方便。分布式版本控制工具有:Git、Mercurial、Bazaar等。
分布式的特点是不需要联网就能工作。不依赖中央服务器,安全性高。
1.2 安装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 三个具有代表性的命令
添加到版本库:
git add
提交到版本库:
git commit
把本地版本库推送到远程版本库:
git push
2 版本控制
2.1 创建版本库
选择合适路径,创建一个空目录
使用
git init
初始化git管理的目录
然后我们添加文件到版本库
编辑文本文件readme.txt
添加到版本库:
git add
提交到版本库:
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 status
和git diff
查看。
git log查看仓库历史纪录
git log
命令显示从最近到最远的提交日志。
2.3 版本回退
git reset回退到指定版本
git reset
具有三个参数,分别是soft
、hard
和mixed
。
--soft
参数告诉Git重置HEAD到另外一个commit,但也到此为止。如果你指定–soft参数,Git将停止在那里而什么也不会根本变化。这意味着index,working copy都不会做任何变化,所有的在original HEAD和你重置到的那个commit之间的所有变更集仍然在stage(index)区域中。
--hard
参数将会将重置HEAD返回到另外一个commit(取决于~12的参数),重置index以便反映HEAD的变化,并且重置working copy也使得其完全匹配起来。这是一个比较危险的动作,具有破坏性,数据因此可能会丢失!如果真是发生了数据丢失又希望找回来,那么只有使用git reflog
命令了。
--mixed
是reset的默认参数,也就是当你不指定任何参数时的参数。它将重置HEAD到另外一个commit,并且重置index以便和HEAD比配,但是也到此为止。working copy不会被更改。所以所有从original HEAD到你重置到的那个commit之间的所有变更仍然保存在working copy中,被标示为已变更,但是并未staged的状态。
Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上个版本就是HEAD^^。往上N个版本可以写为HEAD~N,如上100个版本为HEAD~100。
撤销后再查看记录发现提交记录少了一个
也可以指定回滚的版本号。版本号用git log
查看commit id前7位。
如果我们忘记回退前的版本号,git reflog
命令记录了每一次的命令操作,包含了所有版本的版本号。
2.4 撤销修改
git checkout - - file
该命令会把文件在工作区的修改全部撤销,回到最近一次git commit
或git 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 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_rsa
和id_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
,将之前的内容粘贴上去即可。
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分支的线也越来越长。
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上。
由这个数据结构我们知道,Git创建一个分支很快,因为除了增加一个dev指针,改改HEAD的指向,工作区的文件都没有任何变化!
从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变。
假如我们在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分支。
切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!
因为那个提交是在dev分支上,而master分支此刻的提交点并没有变。
现在,我们把dev分支的工作成果合并到master分支上,git merge
命令用于合并指定分支到当前分支。
合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。
注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
合并完成后,就可以放心地删除dev分支了 使用git branch -d 分支名
。
删除后,查看branch,就只剩下master分支了:
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
4.2 解决冲突
合并分支并非总是这么一帆风顺,有可能遇上冲突问题。
准备新的feature1分支,来模拟冲突问题。
修改readme.txt最后一行,改为:
this changed by feature1 branch..
在feature1分支上提交:
切换到master分支:
Git还会自动提示我们当前master分支比远程的master分支要超前1个提交。
在master分支上把readme.txt文件的最后一行改为:
this changed by master branch..
提交:
现在,master分支和feature1分支各自都分别有新的提交,变成了这样:
这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:
果然冲突了!Git告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交。
git status
也可以告诉我们冲突的文件:
我们可以直接查看readme.txt的内容:
Git用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,我们将最后一行修改如下后保存:
this changed by master and dev branch..
再提交:
现在,master分支和feature1分支变成了下图所示:
用带参数的git log
也可以看到分支的合并情况:
git log --graph --pretty=oneline --abbrev-commit
最后,删除feature1分支:
4.3 分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
我们可以强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
下面我们实战一下non-fast-forward方式的merge。
首先,仍然创建并切换dev分支:
修改readme.txt文件,并提交一个新的commit:
现在,我们切换回master:
准备合并dev分支,请注意–no-ff参数,表示禁用Fast forward。因为本次合并要创建一个新的commit,所以加上-m
参数,把commit描述写进去。
合并后,我们用git log看看分支历史:
可以看到,不使用Fast forward模式,merge后就像这样:
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活,干活都在dev分支上。
也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
4.4 Bug分支
当你接到一个修复bug的任务时,很自然地,你想创建一个分支来修复它。但是等等,当前分支上进行的工作还没有提交。并不是你不想提交,而是工作只进行到一半,还没法提交。如下图,demo.c文件还没有完成,无法提交。
但是,你必须紧急修复该bug,怎么办?幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作。
现在,用git status
查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。
首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
现在模拟修复bug,随便修改readme.txt内容,然后提交:
修复完成后,切换到master分支,并完成合并,最后删除issue分支:
修复完了Bug,是时候接着回到dev分支干活了!
工作区是干净的,刚才的工作现场存到哪去了?用git stash list
命令看看:
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
用
git stash apply
恢复,但是恢复后,stash内容并不删除,你需要用git stash drop
来删除。用
git stash pop
,恢复的同时把stash内容也删了。
这里假设我们不需要保留stash的内容了,使用git stash pop
命令。再用git stash list
查看,就看不到任何stash内容了:
当然了,你可以多次stash,恢复的时候,先用git stash list
查看,然后恢复指定的stash,用命令:
git stash apply stash@{0}
4.5 多人协作
你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
用git remote
查看远程库的信息,或者,用git remote -v显示更详细的信息:
上面显示了可以抓取和推送的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,然后打上就可以了:
比方说要对add merge这次提交打标签,它对应的commit id是3728b64,敲入命令git tag v0.1 6224937
:
再用命令git tag
查看标签:
注意,标签不是按时间顺序列出,而是按字母排序的。可以用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.dat
、letter.dat
和symbol.dat
,digit.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 rebase
d命令的交互命令中,首先逆序存放了我们最新的两次提交,最前面的状态为pick
。下面也提示了我们可以执行哪些命令,这里我们这里只使用它的edit
功能。
将我们要修改的那次提交状态改为edit
或e
,也就是将第一行内容改为:
edit 8cc5dcb add letter.dat
然后保存退出:
git已经提示我们此时已经暂停在了8cc5dc这一次提交上,后面新的提交此时应该被隐藏掉了,查看日志验证我们的判断:
不出所料,添加symbol.dat的那次提交已经被隐藏掉了,添加letter.dat的那次提交已经成为当前最新的提交了,这时候我们就可以轻松对它进行操作了。
Step2 : 修改文件内容
Step3 : git add
并git commit --amend
其实之前的图上已经提示我们如何操作了,先git add
,然后执行命令git commit --amend
提交变更。
Step4 : git rebase --continue
此时就已经完成了对那次提交的修改,查看日志和文件内容,大功告成。
- git使用教程,命令教程
- Git使用教程
- git 使用教程
- Git使用简明教程
- <<git使用快速教程>>
- Git 使用教程
- git 使用教程
- Git初级使用教程
- git@osc使用教程
- Git初级使用教程
- Git 使用教程
- <<git使用快速教程>>
- Git使用教程
- git简单使用教程
- Git 使用教程
- Git使用教程
- Git使用教程
- Git初级使用教程
- memberCache java客户端的使用
- Mysql int类型
- 随记
- Git常用命令及GitHub入门使用
- 求1到100之间的素数
- Git使用教程
- Mysql 修改root密码,并设置远程访问
- Eclipse怎么使用lombok?
- 深入理解Java虚拟机(五)类加载机制
- 「Python」os.system(command)
- 句柄再谈
- 初学易语言,所要准备些什么书籍与资料
- 基本数据类型
- 单调栈+STL——51nod1952 栈