Git和GitHub入门基础
-----------------------------------------
//cd F:/learngit
// 创建仓库
git init // 在当前目录下创建空的git仓库
-----------------------------------------
// 创建文件并放到git仓库所在目录,执行下面命令将文件添加到git仓库
git add fileneme // 添加文件
git add --update // 更新所有修改的文件(添加到暂存区)
git add -A: [<path>]表示把<path>中所有tracked文件中被修改过或已删除文件和所有untracted的文件信息添加到索引库。
省略<path>表示.,即当前目录。
git commit -m "commit msg" // 提交文件
-----------------------------------------
git add filename1
git add filename2, filename3
git commit -m "add 3 files" // 一次提交多个文件
-----------------------------------------
git status // 查看git仓库状态
git diff filename //查看文件不同
// 注意,提交修改和提交新文件是一样的两步:add和commit
-----------------------------------------
git log // 查看日志
git log --pretty=oneline // 查看简化日志
-----------------------------------------
// 版本回退
git reset --hard HEAD^ // 上一个版本
git reset --hard HEAD^^ // 上两个版本
git reset --hard HEAD~100 // 上100个版本
// 撤销回退
git reflog // 记录执行过的每一次命令(可以由此获得相对应版本的commit_id)
git reset --hard commit_id // 回到commit_id对应的版本
-----------------------------------------
// 相关概念
工作区:本例中“F:/learngit”即为工作区;
版本库:工作区有一个(隐藏目录).git,即为Git的版本库;
暂存区(类比购物车):Git版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
第一步是用“git add”把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用“git commit”提交更改,实际上就是把暂存区的所有内容提交到当前分支。
例子(git commit只负责把暂存区的修改提交):
“第一次修改 -> git add -> 第二次修改 -> git commit” // 第二次修改没有被add到暂存区,所以不会被提交到master
“第一次修改 -> git add -> 第二次修改 -> git add -> git commit” // 第二次修改被add到暂存区,所以会被提交到master
-----------------------------------------
// 撤销修改
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令“git checkout -- filename”。(不加“--”表示切换分支)
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令“git reset HEAD filename”,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。
-----------------------------------------
// 删除文件
rm filename // 文件删除(类似于我们在硬盘直接del文件,但版本库依然保留)
// 确实要从版本库中删除
git rm filename // 从版本库中删除
git commit -m "remove filename" // 删除也是一种修改,所以需要提交
git checkout -- filename // 误删,从版本库中恢复
-----------------------------------------
// 远程仓库GitHub(自行注册GitHub账号)
// 1. 创建SSH Key.
ssh-keygen -t rsa -C "youremail@example.com"(本人使用“ yxtxiaotian@163.com ”)
// 一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码.
// 2. 可以在创建key的目录中找到.ssh目录,里面有id_rsa和id_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人.
// 3. 登陆GitHub,打开“Account settings”,“SSH Keys”页面.
// 4. 点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容.
// 5. 为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送.
-----------------------------------------
// 添加远程库
// 1. 登陆GitHub,Create repository在GitHub上创建一个新的Git仓库(learngit).
// 2. GitHub的提示,在本地的learngit仓库下运行命令
$ git remote add origin git@github.com:yangxt225/learngit.git
(删除远程仓库 : $ git remote rm origin)
// 3. 下一步,就可以把本地库的所有内容推送到远程库origin上:
// 由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送到远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令
$ git push -u origin master
// 4. 此后,每次本地提交后,只要有必要,就可以使用命令“git push origin master” 推送最新修改。
// 分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步!
-----------------------------------------
// 从远程库克隆
// 1. 要克隆一个仓库,首先必须知道仓库的地址(如“ git@github.com:yangxt225/learngit.git ”),然后使用git clone命令克隆;
git clone git@github.com:yangxt225/learngit.git
// 2. Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快.
-----------------------------------------
// 分支管理
// 1. 分支的意义:在分支里面修改和提交,并在最终完成一个完整功能的时候,一次性的合并到原来的分支。这样既安全又不影响别人的工作。
// 2. 其他版本控制系统如SVN等都有分支管理,但这些版本控制系统创建和切换分支很慢。而Git可以极其快速(1s级别)的创建、切换和删除分支。
-----------------------------------------
// 创建与合并分支
// 1. 在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支.
// 2. 一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点.
// 3. 每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长.
// 4. 当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上.
// 5. 从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变.
// 6. 假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并.
// 7. 合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支.
-----------------------------------------
// 实例:
$ git checkout -b dev // 创建dev分支,然后切换到dev分支
// git checkout命令加上-b参数表示创建并切换,相当于以下两条命令
$ git branch dev // 创建dev分支
$ git checkout dev // 切换到dev分支
$ git branch // 会列出所有分支,当前分支前面会标一个*号
// 切换到分支,就可以在分支上进行正常修改、提交操作,最后合并到master
$ git merge dev // 合并到master分支,在master分支上,执行下面合并dev分支的命令
// 合并完成后,就可以放心地删除dev分支了
$ git branch -d dev
// 因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全
$ git push origin dev // 将dev分支推送到远程仓库origin,不推送,dev分支只能在本地可见
// 本地版本库删除dev分支,如何同步删除远程仓库分支??
-----------------------------------------
// 解决冲突
// 创建feature1分支
$ git checkout -b feature1
// 修改readme.txt最后一行,改为:Creating a new branch is quick AND simple.
$ git add readme.txt
$ git commit -m "AND simple"
// 切换到master分支
$ git checkout master
// 修改readme.txt最后一行,改为:Creating a new branch is quick & simple.
$ git add readme.txt
$ git commit -m "& simple"
// 合并分支,出现冲突
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
// 可以直接查看readme.txt的内容,修复冲突,重新提交
$ git add readme.txt
$ git commit -m "conflict fixed"
// 用带参数的git log也可以看到分支的合并情况:
$ git log --graph --pretty=oneline --abbrev-commit
$ git branch -d feature1 // 删除分支
// 当Git无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成.
// 用git log --graph命令可以看到分支合并图
-----------------------------------------
// 分支管理策略
// 1. 通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
// 2. 如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息
$ git merge --no-ff -m "merge with no-ff" dev // 因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去
// 3. 在实际开发中,我们应该按照几个基本原则进行分支管理:
// 首先,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。首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:
$ git checkout master
$ git checkout -b issue-101
// 现在修复bug,需要把“Git is free software ...”改为“Git is a free software ...”,然后提交:
$ git add readme.txt
$ git commit -m "fix bug 101"
// 修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:
$ git checkout master
$ git merge --no-ff -m "merged bug fix 101" issue-101
$ git branch -d issue-101
// 太棒了,原计划两个小时的bug修复只花了5分钟!现在,是时候接着回到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 list查看,就看不到任何stash内容了.
// 你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:
$ git stash apply stash@{0}
-----------------------------------------
// Feature分支
// 开发一个新feature,最好新建一个分支;
// 如果要丢弃一个没有被合并过的分支,可以通过“git branch -d <name>”强行删除。
$ git branch -d feature1
-----------------------------------------
// 多人协作
// 当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
// 要查看远程库的信息,用“git remote”:
$ git remote
origin
// 或者,用“git remote -v”显示更详细的信息:
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
// 上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。
--------------------
// 推送分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
// 如果要推送其他分支,比如dev,就改成:
$ git push origin dev
// 但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
1. master分支是主分支,因此要时刻与远程同步;
2. dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
3. bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
4. feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
// 总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!
--------------------
// 抓取分支
// 多人协作时,大家都会往master和dev分支上推送各自的修改。
// 现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下(F:/learngit2/)克隆:
$ git clone git@github.com:yangxt225/learngit.git
// 当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
$ git branch
* master
// 现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev
// 现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:
$ git commit -m "add /usr/bin/env"
$ git push origin dev
--------------------
// 你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送.
// 推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送.
// “git pull”也失败了(There is no tracking information for the current branch),原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接.
$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
$ git pull // 再次pull
Auto-merging hello.py
CONFLICT (content): Merge conflict in hello.py
Automatic merge failed; fix conflicts and then commit the result.
// 这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,add,提交,再push:
$ git commit -m "merge & fix hello.py"
[dev adca45d] 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。
// 这就是多人协作的工作模式,一旦熟悉了,就非常简单。
--------------------
// 小结
// 1. 查看远程库信息,使用git remote -v;
// 2. 本地新建的分支如果不推送到远程,对其他人就是不可见的;
// 3. 从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
// 4. 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
// 5. 建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name;
// 6. 从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
-----------------------------------------
// 标签管理
// 发布一个版本时,我们通常先在版本库中打一个标签,这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
// Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像,但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
-----------------------------------------
// 创建标签
// 在Git中打标签非常简单,首先,切换到需要打标签的分支上, 然后,敲命令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
// 可以看到,v0.9确实打在add merge这次提交上。
--------------------
// 还可以创建带有说明的标签,用-a指定标签名,-m指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 3628164
// 用命令git show <tagname>可以看到说明文字.
// 还可以通过-s用私钥签名一个标签:
$ git tag -s v0.2 -m "signed version 0.2 released" fec145a
// 签名采用PGP签名,因此,必须首先安装gpg(GnuPG),如果没有找到gpg,或者没有gpg密钥对,就会报错:
gpg: signing failed: secret key not available
error: gpg failed to sign the data
error: unable to sign the tag
// 如果报错,请参考GnuPG帮助文档配置Key。
// 用命令git show <tagname>可以看到PGP签名信息.
// 用PGP签名的标签是不可伪造的,因为可以验证PGP签名。验证签名的方法比较复杂,这里就不介绍了.
--------------------
小结
命令git tag <name>用于新建一个标签,默认为HEAD,也可以指定一个commit id;
git tag -a <tagname> -m "blablabla..."可以指定标签信息;
git tag -s <tagname> -m "blablabla..."可以用PGP签名标签;
命令git tag可以查看所有标签。
-----------------------------------------
// 操作标签
// 如果标签打错了,也可以删除:
$ git tag -d v1.0
// 因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
// 如果要推送某个标签到远程,使用命令git push origin <tagname>:
$ git push origin 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
// 要看看是否真的从远程库删除了标签,可以登陆GitHub查看。
--------------------
小结
命令git push origin <tagname>可以推送一个本地标签;
命令git push origin --tags可以推送全部未推送过的本地标签;
命令git tag -d <tagname>可以删除一个本地标签;
命令git push origin :refs/tags/<tagname>可以删除一个远程标签。
-----------------------------------------
// 使用GitHub
// 在GitHub上,利用Git极其强大的克隆和分支功能,广大人民群众真正可以第一次自由参与各种开源项目了。
// 如何参与一个开源项目呢?比如人气极高的bootstrap项目,这是一个非常强大的CSS框架,你可以访问它的项目主页https://github.com/twbs/bootstrap,点“Fork”就在自己的账号下克隆了一个bootstrap仓库,然后,从自己的账号下clone:
git clone git@github.com:yangxt225/bootstrap.git
// 一定要从自己的账号下clone仓库,这样你才能推送修改。如果从bootstrap的作者的仓库地址 git@github.com:twbs/bootstrap.git 克隆,因为没有权限,你将不能推送修改。
--------------------
// Bootstrap的官方仓库twbs/bootstrap、你在GitHub上克隆的仓库my/bootstrap,以及你自己克隆到本地电脑的仓库,他们的关系就像下图显示的那样:
// 如果你想修复bootstrap的一个bug,或者新增一个功能,立刻就可以开始干活,干完后,往自己的仓库推送。
// 如果你希望bootstrap的官方库能接受你的修改,你就可以在GitHub上发起一个pull request。当然,对方是否接受你的pull request就不一定了。
--------------------
// 小结
// 1. 在GitHub上,可以任意Fork开源仓库;
// 2. 自己拥有Fork后的仓库的读写权限;
// 3. 可以推送pull request给官方仓库来贡献代码。
-----------------------------------------
// 自定义Git
// 在安装Git一节中,我们已经配置了user.name和user.email,实际上,Git还有很多可配置项。
// 比如,让Git显示颜色,会让命令输出看起来更醒目:
$ git config --global color.ui true
// 这样,Git会适当地显示不同的颜色.
-----------------------------------------
// 忽略特殊文件
// 有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files ...,有强迫症的童鞋心里肯定不爽。
// 好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件(使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了),然后把要忽略的文件名填进去,Git就会自动忽略这些文件。
// 不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore
--------------------
// 忽略文件的原则是:
// 忽略操作系统自动生成的文件,比如缩略图等;
// 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
// 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件
--------------------
// 例子
// 如果你现在在工作区放入password.txt文件,但你又不能把它交给git,而每次的“git status”却都会提示Untracked files ...。
// 1. 创建一个文件“.gitignore”;
// 2. 把password.txt文件名(包括后缀)写到.gitignore文件里面;
// 3. 把文件(.gitignore)add/commit 到版本库。
// 小结
// 忽略某些文件时,需要编写.gitignore;
// .gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!
-----------------------------------------
// 配置别名
// 有没有经常敲错命令?比如git status?status这个单词真心不好记。如果敲git st就表示git status那就简单多了,当然这种偷懒的办法我们是极力赞成的。我们只需要敲一行命令,告诉Git,以后st就表示status:
$ git config --global alias.st status
// 好了,现在敲“git st”就表示“git status”。
// 当然还有别的命令可以简写,很多人都用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
// 甚至还有人丧心病狂地把lg配置成了:
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的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。
// 配置文件放哪了?每个仓库的Git配置文件都放在.git/config文件中:
$ cat .git/config // 打开查看文件命令
// 别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。
// 而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:
$ cat .gitconfig
// 配置别名也可以直接修改这个文件,如果改错了可以删掉文件重新通过命令配置。
-----------------------------------------
// 搭建Git服务器:自己搭建一台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: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
Cloning into 'sample'...
warning: You appear to have cloned an empty repository.
// 剩下的推送就简单了。
--------------------
// 管理公钥
// 如果团队很小,把每个人的公钥收集起来放到服务器的/home/git/.ssh/authorized_keys文件里就是可行的。如果团队有几百号人,就没法这么玩了,这时,可以用Gitosis来管理公钥。这里我们不介绍怎么玩Gitosis了,几百号人的团队基本都在500强了,相信找个高水平的Linux管理员问题不大。
--------------------
// 管理权限
// 有很多不但视源代码如生命,而且视员工为窃贼的公司,会在版本控制系统里设置一套完善的权限控制,每个人是否有读写权限会精确到每个分支甚至每个目录下。因为Git是为Linux源代码托管而开发的,所以Git也继承了开源社区的精神,不支持权限控制。不过,因为Git支持钩子(hook),所以,可以在服务器端编写一系列脚本来控制提交等操作,达到权限控制的目的。Gitolite就是这个工具。这里我们也不介绍Gitolite了,不要把有限的生命浪费到权限斗争中。
--------------------
// 小结
// 搭建Git服务器非常简单,通常10分钟即可完成;
// 要方便管理公钥,用Gitosis;
// 要像SVN那样变态地控制权限,用Gitolite。
user.name : yangxt225
user.email: yxtxiaotian@163.com
教程网址:
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
其他:
http://blog.csdn.net/aaron_luchen/article/details/10498181
http://www.cnblogs.com/xiaogangqq123/archive/2012/03/19/2405805.html
http://blog.csdn.net/jackystudio/article/details/12249303#comments
http://www.open-open.com/lib/view/open1374049161825.html
http://blog.csdn.net/ichsonx/article/details/8625925
http://blog.csdn.net/hcbbt/article/details/11651229