git使用手册
本文于2320天之前发表,文中内容可能已经过时。
一. 常用命令
1. gitk,输入该命令后,简单的图形方式
2. git config -l,列出配置文件
git config --global user.name "xxx"
git config --global user.email "xxx"
要删除:git config –unset user.username
3. 设置别名
git config alias.con ‘config -l’
则git con等同于git config -l
4. GIT的文件,刚新建立的时候,都为UNTRACKED状态,
建立touch .gitignore 文件,内容为:
.gitignore
xxx(要忽略的文件或文件夹)
则 git add xxx的文件会跟踪是否修改新增删除;
.gitignore的文件,不会显示是否修改,也不显示其信息;
设置排除忽略,使用!符号
*.txt
#注释
!note.txt (忽略所有TXT,不包括note.txt文件)
5. git log查看历史记录
6. 首先,Git必须知道当前版本是哪个版本,
在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,
所以写成HEAD~100
回退到上1个版本(对于GIT ADD,GIT COMMIT后的文件都可以这样做)
git reset –hard HEAD^
回退到某个版本
git reset –hard 3628164(这个是版本号,用git log看)
版本回退
阅读: 838585
现在,你已经学会了修改文件,然后把修改提交到Git版本库,现在,再练习一次,修改readme.txt文件如下:
Git is a distributed version control system.
Git is free software distributed under the GPL.
然后尝试提交:
$ git add readme.txt
$ git commit -m “append GPL”
[master 3628164] append GPL
1 file changed, 1 insertion(+), 1 deletion(-)
像这样,你不断对文件进行修改,然后不断提交修改到版本库里,就好比玩RPG游戏时,每通过一关就会自动把游戏状态存盘,如果某一关没过去,你还可以选择读取前一关的状态。有些时候,在打Boss之前,你会手动存盘,以便万一打Boss失败了,可以从最近的地方重新开始。Git也是一样,每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失。
现在,我们回顾一下readme.txt文件一共有几个版本被提交到Git仓库里了:
版本1:wrote a readme file
Git is a version control system.
Git is free software.
版本2:add distributed
Git is a distributed version control system.
Git is free software.
版本3:append GPL
Git is a distributed version control system.
Git is free software distributed under the GPL.
当然了,在实际工作中,我们脑子里怎么可能记得一个几千行的文件每次都改了什么内容,不然要版本控制系统干什么。版本控制系统肯定有某个命令可以告诉我们历史记录,在Git中,我们用git log命令查看:
$ git log
commit 3628164fb26d48395383f8f31179f24e0882e1e0
Author: Michael Liao askxuefeng@gmail.com
Date: Tue Aug 20 15:11:49 2013 +0800
append GPL
commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao askxuefeng@gmail.com
Date: Tue Aug 20 14:53:12 2013 +0800
add distributed
commit cb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao askxuefeng@gmail.com
Date: Mon Aug 19 17:51:55 2013 +0800
wrote a readme file
git log命令显示从最近到最远的提交日志,我们可以看到3次提交,最近的一次是append GPL,上一次是add distributed,最早的一次是wrote a readme file。
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上–pretty=oneline参数:
$ git log –pretty=oneline
3628164fb26d48395383f8f31179f24e0882e1e0 append GPL
ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file
需要友情提示的是,你看到的一大串类似3628164…882e1e0的是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示,而且你看到的commit id和我的肯定不一样,以你自己的为准。为什么commit id需要用这么一大串数字表示呢?因为Git是分布式的版本控制系统,后面我们还要研究多人在同一个版本库里工作,如果大家都用1,2,3……作为版本号,那肯定就冲突了。
每提交一个新版本,实际上Git就会把它们自动串成一条时间线。如果使用可视化工具查看Git历史,就可以更清楚地看到提交历史的时间线:
git-log-timeline
好了,现在我们启动时光穿梭机,准备把readme.txt回退到上一个版本,也就是“add distributed”的那个版本,怎么做呢?
首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164…882e1e0(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。
现在,我们要把当前版本“append GPL”回退到上一个版本“add distributed”,就可以使用git reset命令:
$ git reset –hard HEAD^
HEAD is now at ea34578 add distributed
–hard参数有啥意义?这个后面再讲,现在你先放心使用。
看看readme.txt的内容是不是版本add distributed:
$ cat readme.txt
Git is a distributed version control system.
Git is free software.
果然。
还可以继续回退到上一个版本wrote a readme file,不过且慢,然我们用git log再看看现在版本库的状态:
$ git log
commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao askxuefeng@gmail.com
Date: Tue Aug 20 14:53:12 2013 +0800
add distributed
commit cb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao askxuefeng@gmail.com
Date: Mon Aug 19 17:51:55 2013 +0800
wrote a readme file
最新的那个版本append GPL已经看不到了!好比你从21世纪坐时光穿梭机来到了19世纪,想再回去已经回不去了,肿么办?
办法其实还是有的,只要上面的命令行窗口还没有被关掉,你就可以顺着往上找啊找啊,找到那个append GPL的commit id是3628164…,于是就可以指定回到未来的某个版本:
$ git reset –hard 3628164
HEAD is now at 3628164 append GPL
版本号没必要写全,前几位就可以了,Git会自动去找。当然也不能只写前一两位,因为Git可能会找到多个版本号,就无法确定是哪一个了。
再小心翼翼地看看readme.txt的内容:
$
现在,你回退到了某个版本,关掉了电脑,第二天早上就后悔了,想恢复到新版本怎么办?找不到新版本的commit id怎么办?
在Git中,总是有后悔药可以吃的。当你用$ git reset –hard HEAD^回退到add distributed版本时,再想恢复到append GPL,就必须找到append GPL的commit id。Git提供了一个命令git reflog用来记录你的每一次命令:
$ git reflog
ea34578 HEAD@{0}: reset: moving to HEAD^
3628164 HEAD@{1}: commit: append GPL
ea34578 HEAD@{2}: commit: add distributed
cb926e7 HEAD@{3}: commit (initial): wrote a readme file
则可以继续 git reset –hard 3628164
7. 我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支
8. git diff HEAD – readme.txt命令可以查看工作区和版本库里面最新版本的区别:
9. 撤销修改
1) 放弃工作区修改,gid add,GIT COMMIT后,放弃工作区修改
$ git checkout – readme.txt
命令git checkout – readme.txt意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
比如test1.txt在GIT ADD后到暂存区,没COMMIT前,要丢掉:
git checkout – test1.txt
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout – file。
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
10. 删除文件
一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit:
$ git rm test.txt
rm ‘test.txt’
$ git commit -m “remove test.txt”
[master d17efd8] remove test.txt
1 file changed, 1 deletion(-)
delete mode 100644 test.txt
现在,文件就从版本库中被删除了。
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
$ git checkout – test.txt
git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
11. 本地库关联远程库:
git remote add origin git@github.com:jackyrong/learngit.git
12. 本地库的所有内容推送到远程库上:
$ git push -u origin master(第一次推送master分支的所有内容;)
只要本地作了提交,就可以通过命令:
$ git push origin master
13. 克隆GIT:
git clone git@github.com:jackyrong/gitskills.git
14. 创建分支
首先,我们创建dev分支,然后切换到dev分支:
$ git checkout -b dev
Switched to a new branch ‘dev’
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch ‘dev’
然后,用git branch命令查看当前分支:
$ git branch
- dev
master
git branch命令会列出所有分支,当前分支前面会标一个*号。
现在,我们把dev分支的工作成果合并到master分支上:
$ git merge dev
git merge命令用于合并指定分支到当前分支。(因为当前切换到DEV了)
合并完成后,就可以放心地删除dev分支了:
$ git branch -d dev
Deleted branch dev (was fec145a).
删除后,查看branch,就只剩下master分支了:
$ git branch
- master
15. 分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
git merge –no-ff -m “merge with no-ff” dev
加上–no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并
16. BUG分支
Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
比如某个文件,只是ADD了,但没有COMMIT,则:
$ git stash
Saved working directory and index state WIP on dev: 6224937 add merge
HEAD is now at 6224937 add merge
然后假设MASTER分支上修复
$ git checkout master
git checkout -b issue-101
修改后
$ git add readme.txt
$ git commit -m “fix bug 101”
修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:
$ git checkout master
Switched to branch ‘master’
Your branch is ahead of ‘origin/master’ by 2 commits.
$ git merge –no-ff -m “merged bug fix 101” issue-101
Merge made by the ‘recursive’ strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-101
Deleted branch issue-101 (was cc17032).
现在,是时候接着回到dev分支干活了!
$ git checkout dev
Switched to branch ‘dev’
$ git status
# On branch dev
nothing to commit (working directory clean)
工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:
$ git stash list
stash@{0}: WIP on dev: 6224937 add merge
工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除;
另一种方式是用git stash pop,恢复的同时把stash内容也删了:
$ git stash pop
17. 强行删除分支
git branch -D feature-vulcan(分支名)
18. 查看远程库的信息:
git remote -v
把本地的东西都推送到远程分支上:
git push origin master
19. 真正开发的时候,
1) git clone git@github.com:jackyrong/learngit.git
clone下来后,默认情况只看到master分支,
要在DEV分支上开发:
git checkout -b dev origin/dev
另外的人先:git pull origin/dev
小结
查看远程库信息,使用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,如果有冲突,要先处理冲突。
20. 标签管理
$ git tag v1.0
git tag查看所有标签
默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,然后打上就可以了:
$ git log –pretty=oneline –abbrev-commit
6a5819e merged bug fix 101
cc17032 fix bug 101
7825a50 merge with no-ff
6224937 add merge
59bc1cb conflict fixed
400b400 & simple
75a857c AND simple
fec145a branch test
d17efd8 remove test.txt
比方说要对add merge这次提交打标签,它对应的commit id是6224937,敲入命令:
$ git tag v0.9 6224937
还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m “version 0.1 released” 3628164
如果标签打错了,也可以删除:
$ git tag -d v0.1
Deleted tag ‘v0.1’ (was e078af9)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令git push origin
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
- [new tag] v1.0 -> v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin –tags
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag ‘v0.9’ (was 6224937)
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
21. 从GITHUB的开源项目中,可以FORK一个出来,用自己的账号
CLONE
git clone git@github.com:jackyrong/bootstrap.git
然后就可以本地修改,然后可以PUSH给远端的真正库
22. rebase 命令将提交到某一分支上的所有修改都移至另一分支上
23. 一个库关联多个GIT
git remote add github git@github.com:michaelliao/learngit.git
然后,先关联GitHub的远程库:
git remote add github git@github.com:michaelliao/learngit.git
注意,远程库的名称叫github,不叫origin了。
接着,再关联码云的远程库:
git remote add gitee git@gitee.com:liaoxuefeng/learngit.git
同样注意,远程库的名称叫gitee,不叫origin。
现在,我们用git remote -v查看远程库信息,可以看到两个远程库:
git remote -v
gitee git@gitee.com:liaoxuefeng/learngit.git (fetch)
gitee git@gitee.com:liaoxuefeng/learngit.git (push)
github git@github.com:michaelliao/learngit.git (fetch)
github git@github.com:michaelliao/learngit.git (push)
如果要推送到GitHub,使用命令:
git push github master
如果要推送到码云,使用命令:
git push gitee master
24. GIT文件的忽略
不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
忽略文件的原则是:
忽略操作系统自动生成的文件,比如缩略图等;
忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
举个例子:
假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
然后,继续忽略Python编译产生的.pyc、.pyo、dist等文件或目录:
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
加上你自己定义的文件,最终得到一个完整的.gitignore文件,内容如下:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
# Python:
*.py[cod]
*.so
*.egg
*.egg-info
dist
build
# My configurations:
db.ini
deploy_key_rsa
最后一步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status命令是不是说working directory clean。
使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。
有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:
$ git add App.class
The following paths are ignored by one of your .gitignore files:
App.class
Use -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行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。
25. 配置别名
git config --global alias.st status //st代替status
二. git大小写问题
1. 问题复现
新建一个 a.js 文件(大小写不敏感的状态下),并提交
修改本地 a.js 变为 A.js,文件内容无变更,无法提交
执行git config core.ignorecase false,修改 大小写敏感 规则,然后提交,查看结果,此时会存在 大小写 同时存在的文件
此时某种机缘下,再次执行 git config core.ignorecase true,大小写不敏感,
此时执行 git push , 即把最新的更新都更新到了 a.js 中
此时再修改 大小写敏感规则为敏感, 执行 git pull ,并不会拿到最新的更新。比如自己想要的是第一次修改后的 A.js ,但是服务器有一个没有更新的 A.js 和 有更新的 a.js,而你只能拿到前者,所以就会遇到各种各样的坑……
2. 解决办法
执行git config –global core.ignorecase false,全局设置 大小写敏感 。
2.1. 文件变更比较少的情况
直接使用以下命令重命名文件,在 git 中不要直接修改文件名,最好的办法是使用下面的方式,
1 | git mv -f [你想要删掉的文件] [你想要留下的文件] |
这个命令的目的就是删除不需要的大小写同名文件,修改后 git push 提交变更即可。
tips:
因为 git 默认大小写不敏感,所以最好添加项目配置文件,设置 大小写敏感。
1 | touch .gitconfig |
2.2. 变更比较多,并且拥有分支较高权限
- 在 github 删除该分支
- 本地执行 git rm -r –cached . (注意后面‘点号’)
- 然后重新 git push,就ok了
- 此法不太好,有点暴力,容易出问题,但适用于 变更发生于近期的情况。
3. 总结
其实看解决办法的话,只是一个很小的问题,但是出现的 bug 确实是让人很头疼的,因为 mac windows 在不设置大小写敏感规则的时候默认大小写是不敏感,项目部署的机器是 Linux 的,而 Linux 是大小写敏感的。所以这样的问题平时不易发现,本地调试的时候大部分时候并不会出错误,只有在项目部署的时候问题才会显示出来。
三. GitHub等配置SSH Key
1 | https://github.com/myhhub/CTK-project.git |
上面两个地址展示的是同一个项目,但是这两个地址之间有什么联系呢?
前者是https url 直接有效网址打开,但是用户每次通过git提交的时候都要输入用户名和密码,有没有简单的一点的办法,一次配置,永久使用呢?当然,所以有了第二种地址,也就是SSH URL,那如何配置就是本文要分享的内容。
GitHub配置SSH Key的目的是为了帮助我们在通过git提交代码是,不需要繁琐的验证过程,简化操作流程。
步骤
1. 设置git的user name和email
如果你是第一次使用,或者还没有配置过的话需要操作一下命令,自行替换相应字段。
1 | git config --global user.name "myhhub" |
说明:git config –list 查看当前Git环境所有配置,还可以配置一些命令别名之类的。
2. 检查是否存在SSH Key
1 | cd ~/.ssh |
如果没有SSH Key,则需要先生成一下
1 | ssh-keygen -t rsa -C "yh_ma@qq.com" |
执行之后继续执行以下命令来获取SSH Key
1 | cd ~/.ssh |
3. 获取SSH Key
1 | cat id_rsa.pub |
4. GitHub添加SSH Key
1 | GitHub点击用户头像,选择setting |
新建一个SSH Key
取个名字,把之前拷贝的秘钥复制进去,添加就好啦。
5. 验证和修改
测试是否成功配置SSH Key
1 | ssh -T git@github.com |
之前已经是https的链接,现在想要用SSH提交怎么办?
直接修改项目目录下 .git文件夹下的config文件,将地址修改为SSH地址。
四. 代理配置(Git HTTP+SSH)
1. HTTP 代理
HTTP 代理相对简单
1 | # HTTP 代理 |
注意这里的 socks5
仅仅是代理使用的协议,它依然是针对 http 设置的,所以仅对 http 协议的仓库有效。使用 git@xxx
这种 ssh 连接的不会使用代理。
也可以分域名设置代理:
1 | # 设置代理 |
2. SSH 代理
SSH 代理需要在密钥目录 (~/.ssh
) (Windows 下是 C:\Users\{UserName}\.ssh
) 新建一个 config
文件,没有后缀名。
Linux 系统写入以下配置(未验证):
1 | # 需要 netcat |
Windows:
1 | # -S 为 socks, -H 为 HTTP |
如果找不到
connect
命令那么指定其绝对路径,一般在 git 安装目录下\mingw64\bin\connect.exe
.赠送一个
connect
的官方文档。
也可以分域名代理:
1 | Host github.com |
五. 简单的代码提交流程
- git clone 克隆GIT
- git status 查看工作区代码相对于暂存区的差别
- git add . 将当前目录下修改的所有代码从工作区添加到暂存区 . 代表当前目录
- git commit -m ‘注释’ 将缓存区内容添加到本地仓库
- git push origin master 将本地版本库推送到远程服务器,
- origin是远程主机,master表示是远程服务器上的master分支,分支名是可以修改的
1. Git add
git add [参数] <路径> 作用就是将我们需要提交的代码从工作区添加到暂存区,就是告诉git系统,我们要提交哪些文件,之后就可以使用git commit命令进行提交了。
为了方便下面都用 . 来标识路径, . 表示当前目录,路径可以修改,下列操作的作用范围都在版本库之内。
git add .
不加参数默认为将修改操作的文件和未跟踪新添加的文件添加到git系统的暂存区,注意不包括删除git add -u .
-u 表示将已跟踪文件中的修改和删除的文件添加到暂存区,不包括新增加的文件,注意这些被删除的文件被加入到暂存区再被提交并推送到服务器的版本库之后这个文件就会从git系统中消失了。git add -A .
-A 表示将所有的已跟踪的文件的修改与删除和新增的未跟踪的文件都添加到暂存区。
2. Git commit
git commit 主要是将暂存区里的改动给提交到本地的版本库。每次使用git commit 命令我们都会在本地版本库生成一个40位的哈希值,这个哈希值也叫commit-id,
commit-id 在版本回退的时候是非常有用的,它相当于一个快照,可以在未来的任何时候通过与git reset的组合命令回到这里.
- git commit -m ‘message’
-m 参数表示可以直接输入后面的“message”,如果不加 -m参数,那么是不能直接输入message的,而是会调用一个编辑器一般是vim来让你输入这个message,
message即是我们用来简要说明这次提交的语句。
git commit -am ‘message’ -am等同于-a -m
-a参数可以将所有已跟踪文件中的执行修改或删除操作的文件都提交到本地仓库,即使它们没有经过git add添加到暂存区,
注意: 新加的文件(即没有被git系统管理的文件)是不能被提交到本地仓库的。
3. Git push
在使用git commit命令将修改从暂存区提交到本地版本库后,只剩下最后一步将本地版本库的分支推送到远程服务器上对应的分支了,如果不清楚版本库的构成,可以查看我的另一篇,git 仓库的基本结构。
git push的一般形式为 git push <远程主机名> <本地分支名> <远程分支名> ,例如 git push origin master:refs/for/master ,即是将本地的master分支推送到远程主机origin上的对应master分支, origin 是远程主机名。第一个master是本地分支名,第二个master是远程分支名。
git push origin master
如果远程分支被省略,如上则表示将本地分支推送到与之存在追踪关系的远程分支(通常两者同名),如果该远程分支不存在,则会被新建git push origin :refs/for/master
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支,等同于 git push origin –delete mastergit push origin
如果当前分支与远程分支存在追踪关系,则本地分支和远程分支都可以省略,将当前分支推送到origin主机的对应分支git push
如果当前分支只有一个远程分支,那么主机名都可以省略,形如 git push,可以使用git branch -r ,查看远程的分支名关于 refs/for:
refs/for 的意义在于我们提交代码到服务器之后是需要经过code review 之后才能进行merge的,而refs/heads 不需要
六.git-lfs
什么是 git-lfs
Github 对文件大小的限制
如果你在命令行用 git push
> 50 MB 的文件,你会收到一个 warning
,但是你仍然可以正常 push
,但是 > 100 MB 的时候就无法 push
了
如果你在浏览器要上传文件的话,限制更为严重,不能超过 25 MB
另外有几点值得注意:
- Github 建议仓库的大小理想情况下不要超过 1 GB,最好不要超过 5 GB
- Github 从来不建议把仓库当成一种备份工具
为什么需要 gif-lfs
前面提到的 Github 对文件大小的限制是一点
另外因为每次我们在使用 git commit
的时候,其实是给当前的仓库创建了一次快照,本质是全仓库的克隆,如果大文件太多是很不好的,你的 Git 仓库会越来越大
什么情况下不需要用 gif-lfs
- 文件没有超过限制当然就没有必要用了
- 如果是要分发二进制文件(比如 *.exe)等,此时直接用 Github 提供的 release 功能就好了
git-lfs
原理
使用 gif-lfs
之后,在仓库中存储的其实是对大文件的引用,可以理解为指针。而真正的大文件托管在 Git Lfs 的服务器上
Github 给不同用户的 git-lfs
提供的额度不一样,免费用户和 Pro 用户都是 2 GB
引用文件长什么样子
比如官方文档里面提到的例子:
1 | version https://git-lfs.github.com/spec/v1 |
其中 version
是你正在使用的 git-lfs
的版本,oid
是标志符(id),size
是文件的真实大小
开始使用 git-lfs
如何安装 git-lfs
(Mac 环境下)
1 | > brew install git-lfs |
Case 1. 从 0 开始配置使用 git-lfs
我们要指定 git-lfs
会把哪些文件当作大文件,指定方式比如有:
- 指定文件后缀名——
git lfs track "*.filetype"
- 指定某个目录下的所有文件——
git lfs track "directory/*"
- 具体指定某个文件——
git lfs track "path/to/file"
1 | > mkdir <repo> |
Case 2. 要在已有的仓库上用 git-lfs
追踪某些文件
此时只是简单的使用 git lfs track ""
是没用的,因为你之前的 commit 已经生成了快照,你无法追踪历史中的这些大文件。
git-lfs
只会在你开始设置的此刻之后追踪新生成的指定文件
可以快速做个验证,假设我们还在这个仓库里⬇️
1 | > ls > test1.txt |
正确的方法是使用 git lfs migrate
,这里只列举了简单的用法,更复杂的可以看看手册。比如可以用 --include-ref=
指定分支,多个分支的时候最好一个分支一个分支地迁移,最后是 git push --all -f
1 | > git lfs migrate import --include="*.txt" # 在当前分支上执行 |
Case 3. 不再跟踪某些文件
1 | > git lfs untrack "*.filetype" |
其他常用命令
- 查看当前
git-lfs
正在追踪的文件类型——git lfs track
- 查看当前
git-lfs
正在追踪哪些文件——git lfs ls-file
七.Git的patch相关操作
用format-patch获取patch
format-patch是比diff更新的生成patch方式,可以用git apply
和git am
合并patch,而diff只能利用apply方式
基本用法:
1 | git format-patch xxxx.patch |
对不同分支获取patch,
用diff获取patch
基本用法:
1 | git diff > xxxx.patch |
这样将git diff
的输出放在一个文件中,而diff的输出就是修改的补丁,是tracked
的文件的修改记录(相对于commit在库中的修改)。
如果有新增的文件,并不在Git管理之内,也就是还没有commit在仓库中的文件,执行如下:
1 | git diff --cached > modified.patch |
如果还包含二进制文件,例如图片等
1 | git diff --cached --binary > modified.patch |
对某个commit生成patch
先用git log
找到两个commit记录的签名,然后利用:
1 | git diff xxxxx yyyyy > modified.patch |
这里xxxxx和yyyyy分别是两个commit的签名。
am命令应用patch
基本用法:
1 | git am xxxx.patch |
打补丁:
1 | git am --signoff < xxxx.patch |
使用-s或–signoff选项,可以commit信息中加入Signed-off-by信息
apply命令应用patch
将一个patch应用到Git仓库中的命令是:
1 | git apply modified.patch |
不过在应用之前应该先检查patch文件:
1 | git apply --stat modified.patch |
检查能否应用成功:
1 | git apply --check modified.patch |