Git 详细教程 完全版
创建版本库
$ git init //初始化 $ git status //查看当前仓库状态 $ git diff //查看版本差异
版本回退
提交日志:
git log
命令显示从最近到最远的提交日志, 如果嫌输出信息太多,看得眼花缭乱的,可以试试加上 --pretty=oneline
参数:
$ git log //命令显示从最近到最远的提交日志 $ git log --pretty=oneline //一行显示
版本回退:
首先,Git 必须知道当前版本是哪个版本,在 Git 中,用 HEAD
表示当前版本,也就是最新的提交3628164...882e1e0
,上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成 HEAD~100
。
$ git reset --hard HEAD^
想再回去已经回不去了,肿么办?
$ git reset --hard 3628164 //版本号
版本号没必要写全,前几位就可以了,Git 会自动去找。当然也不能只写前一两位,因为 Git 可能会找到多个版本号,就无法确定是哪一个了。
工作区和暂存区
工作区(Working Directory)
就是你在电脑里能看到的目录,比如我的 learngit 文件夹就是一个工作区
版本库(Repository)
工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为 stage(或者叫 index)的暂存区,还有Git为我们自动创建的第一个分支 master,以及指向 master 的一个指针叫HEAD
。
第一步是用 git add 把文件添加进去,实际上就是把文件修改添加到暂存区:
$ git add . //把当前文件所有修改的文件添加到暂存区 $ git add app/ --all //把app/开头的所有目录下修改的文件添加到暂存区中
第二步是用 git commit 提交更改,实际上就是把暂存区的所有内容提交到当前分支:
$ git commit -m 'xxxx' //把暂存区的所有内容提交到当前分支,并加入注释 $ git commit -m 'xxxx' . //把当前目录下的内容提交到当前分支,并加入注释
因为我们创建Git版本库时,Git自动为我们创建了唯一一个 master 分支,所以,现在,git commit
就是往 master 分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
撤销修改
$ git checkout -- readme.txt //把readme.txt文件在工作区的修改全部撤销,这里有两种情况
一种是 readme.txt 自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是 readme.txt 已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
注意:git checkout -- file 命令中的 -- 很重要,没有 --,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到 git checkout 命令。
删除文件
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用 rm 命令删了:
$ rm test.txt
这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status 命令会立刻告诉你哪些文件被删除了。
现在你有两个选择:
1、确定要从版本库中删除该文件,那就用命令 git rm 文件名 删掉,并且 git commit '说明'
$ git rm readme.txt //删除文件 $ git commit -m '注释' //添加注释
2、另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本 git checkout -- test.txt
$ git checkout --readme.txt //回复误删的文件
远程仓库
第1步:创建 SSH Key。在用户主目录下,看看有没有 .ssh 目录,如果有,再看看这个目录下有没有 id_rsa 和 id_rsa.pub 这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开 Shell(Windows下打开Git Bash),创建 SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com" //你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可
如果一切顺利的话,可以在用户主目录里找到 .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 文件的内容
修改远程仓库地址
$ git remote set-url origin http://linyan:12345@106.200.200.206:8082/linyan/element.git $ git remote set-url origin http://106.200.200.206:8082/linyan/element.git
查看远程仓库地址命令
$ git remote -v
拉取远程仓库代码,是从远程获取master分支的内容到本地.
$ git pull origin master
分支管理
创建与合并分支、删除分支
理论:
一开始的时候,master 分支是一条线,Git 用 master 指向最新的提交,再用HEAD
指向 master,就能确定当前分支,以及当前分支的提交点:
每次提交,master 分支都会向前移动一步,这样,随着你不断提交,master 分支的线也越来越长。
当我们创建新的分支,例如创建 dev 时,Git 新建了一个指针叫 dev,指向 master 相同的提交,再把 HEAD 指向 dev,就表示当前分支在 dev 上:
新提交一次后,dev 指针往前移动一步,而 master 指针不变:
假如我们在 dev 上的工作完成了,就可以把 dev 合并到 master 上。Git 怎么合并呢?最简单的方法,就是直接把 master 指向 dev 的当前提交,就完成了合并:
合并完分支后,甚至可以删除 dev 分支。删除 dev 分支就是把 dev 指针给删掉,删掉后,我们就剩下了一条 master 分支:
实践:
首先,我们创建 dev 分支,然后切换到 dev 分支:
$ git checkout -b dev
Switched to a new branch 'dev'
然后,用 git branch 命令查看当前分支:
$ git branch
* dev
master
git branch 命令会列出所有分支,当前分支前面会标一个 * 号。
然后,我们就可以在 dev 分支上正常提交,比如对 readme.txt 做个修改,加上一行:
$ git add readme.txt
$ git commit -m "branch test"
现在,dev 分支的工作完成,我们就可以切换回 master 分支:
$ git checkout master
现在,我们把 dev 分支的工作成果合并到 master 分支上:
$ git merge dev
git merge 命令用于合并指定分支到当前分支。合并后,再查看 readme.txt 的内容,就可以看到,和 dev 分支的最新提交是完全一样的。
合并完成后,就可以放心地删除 dev 分支了:
$ git branch -d dev
删除后,查看 branch,就只剩下 master 分支了:
$ git branch
* master
总结:
查看分支:git branch
创建分支:git branch < name >
切换分支:git checkout < name >
创建+切换分支:git checkout -b < name >
合并某分支到当前分支:git merge < name >
删除分支:git branch -d < name >
解决冲突
1、准备新的 feature1 分支,继续我们的新分支开发:
$ git checkout -b feature1
2、修改 readme.txt 最后一行,改为:
Creating a new branch is quick AND simple.
3、在 feature1 分支上提交:
$ git add readme.txt
$ git commit -m "AND simple"
4、切换到 master 分支:
$ git checkout master
在 master 分支上把 readme.txt 文件的最后一行改为:
Creating a new branch is quick & simple.
提交:
$ git add readme.txt
$ git commit -m "& simple"
现在,master
分支和feature1
分支各自都分别有新的提交,变成了这样:
这种情况下,Git 无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:
$ git merge feature1
果然冲突了!Git 告诉我们,readme.txt 文件存在冲突,必须手动解决冲突后再提交。git status 也可以告诉我们冲突的文件:
$ git status
我们可以直接查看 readme.txt 的内容:
Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. <<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1 Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存: Creating a new branch is quick and simple.
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 "add merge"
现在,我们切换回 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
* 7825a50 merge with no-ff |\ | * 6224937 add merge |/ * 59bc1cb conflict fixed ...
分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master 分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在 dev 分支上,也就是说,dev 分支是不稳定的,到某个时候,比如1.0版本发布时,再把 dev 分支合并到 master 上,在 master 分支发布1.0版本;
你和你的小伙伴们每个人都在 dev 分支上干活,每个人都有自己的分支,时不时地往 dev 分支上合并就可以了。
Bug分支
软件开发中,bug 就像家常便饭一样。有了 bug 就需要修复,在 Git 中,由于分支是如此的强大,所以,每个 bug 都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在 dev 上进行的工作还没有提交:
并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
幸好,Git 还提供了一个 stash 功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:
$ git stash
现在,用 git status 查看工作区,就是干净的(除非有没有被 Git 管理的文件),因此可以放心地创建分支来修复 bug。
1、首先确定要在哪个分支上修复 bug,假定需要在master分支上修复,就从 master 创建临时分支:
$ git checkout master
$ git checkout -b issue-101
2、现在修复 bug,需要把“Git is free software ...”改为“Git is a free software ...”,然后提交:
$ git add readme.txt
$ git commit -m "fix bug 101"
3、修复完成后,切换到 master 分支,并完成合并,最后删除 issue-101分支:
$ git checkout master
$ git merge --no-ff -m "merged bug fix 101" issue-101
$ git branch -d issue-101
4、接着回到 dev 分支干活了!
$ git checkout dev
$ git status
工作区是干净的,刚才的工作现场存到哪去了?用 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
再用 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 分支。
现在,你终于接到了一个新任务:开发代号为 Vulcan 的新功能,该功能计划用于下一代星际飞船。
于是准备开发:
$ git checkout -b feature-vulcan
5分钟后,开发完毕:
$ git add vulcan.py
$ git status
$ git commit -m "add feature vulcan"
切回 dev,准备合并:
$ git checkout dev
一切顺利的话,feature 分支和 bug 分支是类似的,合并,然后删除。
但是,就在此时,接到上级命令,因经费不足,新功能必须取消!
虽然白干了,但是这个分支还是必须就地销毁:
$ git branch -d feature-vulcan
销毁失败。Git友情提醒,feature-vulcan 分支还没有被合并,如果删除,将丢失掉修改,如果要强行删除,需要使用命令 git branch -D feature-vulcan。
现在我们强行删除:
$ git branch -D feature-vulcan
删除成功!
总结:
开发一个新 feature,最好新建一个分支;
如果要丢弃一个没有被合并过的分支,可以通过 git branch -D < name > 强行删除。
多人协作
当你从远程仓库克隆时,实际上 Git 自动把本地的 master 分支和远程的 master 分支对应起来了,并且,远程仓库的默认名称是 origin。
要查看远程库的信息,用 git remote:
$ git remote
执行结果:
origin
或者,用 git remote -v 显示更详细的信息:
$ git remote -v
执行结果:
origin http://192.168.1.8/awsome_yun/backend.git (fetch) origin http://192.168.1.8/awsome_yun/backend.git (push)
上面显示了可以抓取和推送的 origin 的地址。如果没有推送权限,就看不到 push 的地址。
修改远程推送地址
这里使用 git remote set-url 命令来修改远程地址。另外可以加上你的用户名和密码,这样推送的时候就可以免输入用户名密码了。
格式:
git remote set-url origin http://用户名:密码@192.168.1.8/linyan/baidu_screen.git
例如:
git remote set-url origin http://linyan:12345678@192.168.1.8/linyan/baidu_screen.git
推送分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git 就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
如果要推送其他分支,比如 dev,就改成:
$ git push origin dev
但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master 分支是主分支,因此要时刻与远程同步;
dev 分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug 分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个 bug;
feature 分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
抓取分支
多人协作时,大家都会往 master 和 dev 分支上推送各自的修改。
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:
$ git clone git@github.com:michaelliao/learngit.git
结果:
Cloning into 'learngit'... remote: Counting objects: 46, done. remote: Compressing objects: 100% (26/26), done. remote: Total 46 (delta 16), reused 45 (delta 15) Receiving objects: 100% (46/46), 15.69 KiB | 6 KiB/s, done. Resolving deltas: 100% (16/16), done.
当你的小伙伴从远程库 clone 时,默认情况下,你的小伙伴只能看到本地的 master 分支。不信可以用 git branch 命令看看:
$ git branch
* master
创建远程 dev 分支
现在,你的小伙伴要在 dev 分支上开发,就必须创建远程 origin 的 dev 分支到本地,于是他用这个命令创建本地 dev 分支:
$ git checkout -b dev origin/dev
现在,他就可以在 dev上继续修改,然后,时不时地把 dev 分支 push 到远程:
$ git commit -m "add /usr/bin/env"
[dev 291bea8] add /usr/bin/env 1 file changed, 1 insertion(+)
推送到远程 dev 分支:
$ git push origin dev
Counting objects: 5, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 349 bytes, done. Total 3 (delta 0), reused 0 (delta 0) To git@github.com:michaelliao/learngit.git fc38031..291bea8 dev -> dev
你的小伙伴已经向 origin/dev 分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送:
推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单。
Git 已经提示我们,先用 git pull 把最新的提交从 origin/dev 抓下来,然后,在本地合并,解决冲突,再推送:
$ git pull
git pull 也失败了,原因是没有指定本地 dev 分支与远程 origin/dev 分支的链接,根据提示,设置 dev 和 origin/dev 的链接:
--set-upstream 建立当前分支与远程分支的映射关系
$ git branch --set-upstream dev origin/dev
或
$ git branch -u dev origin/dev
再 pull:
$ git pull
这回 git pull 成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再 push:
$ git commit -m "merge & fix hello.py"
$ git push 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。
这就是多人协作的工作模式,一旦熟悉了,就非常简单了。
总结:
- 查看远程库信息,使用 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,如果有冲突,要先处理冲突。
标签管理
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
Git 的标签虽然是版本库的快照,但其实它就是指向某个 commit 的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
Git 有 commit,为什么还要引入 tag?
“请把上周一的那个版本打包发布,commit 号是 6a5819e...”
“一串乱七八糟的数字不好找!”
如果换一个办法:
“请把上周一的那个版本打包发布,版本号是v1.2”
“好的,按照 tag v1.2 查找 commit 就行!”
所以,tag 就是一个让人容易记住的有意义的名字,它跟某个 commit 绑在一起。
创建标签:
在Git中打标签非常简单,首先,切换到需要打标签的分支上:
$ git branch * dev master
$ git checkout master
然后,敲命令 git tag <name> 就可以打一个新标签:
$ git tag v1.0
可以用命令 git tag 查看所有标签:
$ git tag v1.0
默认标签是打在最新提交的 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
再用命令 git tag 查看标签:
$ git tag v0.9 v1.0
注意,标签不是按时间顺序列出,而是按字母排序的。可以用 git show <tagname> 查看标签信息:
$ git show v0.9
commit 622493706ab447b6bb37e4e2a2f276a20fed2ab4 Author: Michael Liao <askxuefeng@gmail.com> Date: Thu Aug 22 11:22:08 2013 +0800 add merge ...
可以看到,v0.9 确实打在 add merge 这次提交上。
创建带有说明的标签
用 -a 指定标签名,-m 指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164
用命令 git show <tagname> 可以看到说明文字:
$ git show v0.1
tag v0.1 Tagger: Michael Liao <askxuefeng@gmail.com> Date: Mon Aug 26 07:28:11 2013 +0800 version 0.1 released commit 3628164fb26d48395383f8f31179f24e0882e1e0 Author: Michael Liao <askxuefeng@gmail.com> Date: Tue Aug 20 15:11:49 2013 +0800 append GPL
操作标签
删除标签:
$ git tag -d v0.1
Deleted tag 'v0.1' (was e078af9)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
推送标签到远程
推送单个标签到远程,使用命令 git push origin <tagname>:
$ 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 push origin --tags
Counting objects: 1, done. Writing objects: 100% (1/1), 554 bytes, done. Total 1 (delta 0), reused 0 (delta 0) To git@github.com:michaelliao/learngit.git * [new tag] v0.2 -> v0.2 * [new tag] v0.9 -> v0.9
删除远程标签
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was 6224937)
然后,从远程删除。删除命令也是 push,但是格式如下:
$ git push origin :refs/tags/v0.9
To git@github.com:michaelliao/learngit.git - [deleted] v0.9
要看看是否真的从远程库删除了标签,可以登陆远程代码库查看。
自定义Git
比如,让 Git 显示颜色,会让命令输出看起来更醒目:
$ git config --global color.ui true
这样,Git会适当地显示不同的颜色,比如 git status 命令,文件名就会标上颜色。
忽略特殊文件
有些时候,你必须把某些文件放到 Git 工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次 git status 都会显示 Untracked files ...,有强迫症的童鞋心里肯定不爽。
好在 Git 考虑到了大家的感受,这个问题解决起来也很简单,在 Git 工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git 就会自动忽略这些文件。
不需要从头写 .gitignore 文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
忽略文件的原则是:
- 忽略操作系统自动生成的文件,比如缩略图等;
- 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
- 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。
举个例子:
假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:
# Windows:
Thumbs.db
ehthumbs.db
Desktop.ini
加上你自己定义的文件,最终得到一个完整的.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 status?status 这个单词真心不好记。
如果敲 git st 就表示 git status 那就简单多了,当然这种偷懒的办法我们是极力赞成的。
我们只需要敲一行命令,告诉 Git,以后 st 就表示 status:
$ git config --global alias.st status
好了,现在敲 git st 看看效果。
当然还有别的命令可以简写,很多人都用 co 表示 checkout,ci 表示 commit,br 表示 branch:
$ git config --global alias.co checkout $ git config --global alias.ci commit $ git config --global alias.br branch
以后提交就可以简写成:
$ git ci -m "bala bala bala..."
--global 参数是全局参数,也就是这些命令在这台电脑的所有 Git 仓库下都有用。
在撤销修改一节中,我们知道,命令 git reset HEAD file 可以把暂存区的修改撤销掉(unstage),重新放回工作区。既然是一个 unstage 操作,就可以配置一个 unstage 别名:
$ git config --global alias.unstage 'reset HEAD'
当你敲入命令:
$ git unstage test.py
实际上Git执行的是:
$ git reset HEAD test.py
配置一个 git last,让其显示最后一次提交信息:
$ git config --global alias.last 'log -1'
这样,用 git last 就能显示最近一次的提交:
$ git last commit adca45d317e6d8a4b23f9811c3d7b7f0f180bfe2 Merge: bd6ae48 291bea8 Author: Michael Liao <askxuefeng@gmail.com> Date: Thu Aug 22 22:49:22 2013 +0800
merge & fix hello.py
甚至还有人丧心病狂地把 log 配置成了:
$ git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
来看看 git log 的效果:
配置文件
配置 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:michaelliao/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 Cheat Sheet,建议打印出来备用:Git Cheat Sheet
Git 取消跟踪已版本控制的文件
git 不再追踪文件改动 git update-index --assume-unchanged filePath
git 恢复追踪文件改动 git update-index —no-assume-unchanged filePath
git 删除被管理的文件 git rm —cached filePath
git 删除被管理的文件夹 git rm -r -f —cached filePath
命令行指令 HTTP
Git 全局设置 http
git config --global user.name "张三"
git config --global user.email "youremail@qq.com"
创建新版本库
git clone http://192.168.1.8/linyan/element.git
cd test
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
已存在的文件夹
cd existing_folder
git init
git remote add origin http://192.168.1.8:8082/linyan/element.git
git add .
git commit -m "Initial commit"
git push -u origin master
已存在的 Git 版本库
cd existing_repo
git remote add origin http://192.168.1.8:8082/linyan/element.git
git push -u origin --all
git push -u origin --tags
命令行指令 SSH
Git 全局设置 ssh
git config --global user.name "张三"
git config --global user.email "youremail@qq.com"
创建新版本库
git clone git@192.168.1.8:linyan/test.git
cd test
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
已存在的文件夹
cd existing_folder
git init
git remote add origin git@192.168.1.8:linyan/test.git
git add .
git commit -m "Initial commit"
git push -u origin master
已存在的 Git 版本库
cd existing_repo
git remote add origin git@192.168.1.8:linyan/test.git
git push -u origin --all
git push -u origin --tags
从远程库克隆:
git clone git@github.com:michaelliao/gitskills.git