Git
部分来源:
Git基本理论
三个区域
-
Workspace:工作区,就是平时存放项目代码的地方,即git文件夹
-
Index / Stage:暂存区,用于临时存放你的改动,事实上它只是一个文件,保存即将提交到文件列表信息
-
Repository:仓库区(或本地仓库),就是安全存放数据的位置,这里面有你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
-
Remote:远程仓库,托管代码的服务器,可以简单的认为是你项目组中的一台电脑用于远程数据交换
本地的三个区域确切的说应该是git仓库中HEAD指向的版本:
-
Directory:使用Git管理的一个目录,也就是一个仓库,包含我们的工作空间和Git的管理空间。
-
WorkSpace:需要通过Git进行版本控制的目录和文件,这些目录和文件组成了工作空间。
-
.git:存放Git管理信息的目录,初始化仓库的时候自动创建。
-
Index/Stage:暂存区,或者叫待提交更新区,在提交进入repo之前,我们可以把所有的更新放在暂存区。
-
Local Repo:本地仓库,一个存放在本地的版本库;HEAD会只是当前的开发分支(branch)。
-
Stash:隐藏,是一个工作状态保存栈,用于保存/恢复WorkSpace中的临时状态。
工作流程
git的工作流程一般是这样的: 1、在工作目录中添加、修改文件; 2、将需要进行版本管理的文件放入暂存区域; 3、将暂存区域的文件提交到git仓库。
因此,git管理的文件有三种状态:已修改(modified),已暂存(staged),已提交(committed)
工作区和暂存区
-
版本库是工作区中的隐藏目录文件
.git
,版本库中最重要的是stage暂存区;此外git还自动创建了第一个分支master
和指针HEAD
-
文件修改先通过
add
添加到stage暂存区,然后再统一使用commit
提交到主分支,并清空暂存区
管理修改
-
Git管理的是修改而不是文件,未
add
添加到暂存区的修改不会被commit
提交到主分支
分支管理
每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。
对不同分支的操作实际上是对不同指针的操作,所以速度很快
-
目前只有一条时间线,即主分支(
master
分支),HEAD
指针指向master
,master
指向提交。每次提交master
分支都会向前移动一步。
-
创建一个新分支
dev
(即增加一个指针),再改变HEAD
的指向,对工作区的修改和提交就是针对dev
分支了
-
合并分支时,只需要将
master
指向当前dev
所指的位置,就完成了合并;删除分支时也只需要删除指针即可。
-
当分别对
feature1
和master
进行不同的修改后merge
合并,会发生冲突,git status
中也会提示。此时查看文件,Git用<<<<<<<
,=======
,>>>>>>>
标记出不同分支的内容,进行修改后再提交
-
最后再删除
feature1
分支即可
合并有冲突时,会将冲突的内容写入到你的文件中,你解决冲突就是改这个文件,然后
add
commit
,这就完成了一次合并时冲突的解决过程
分支策略
-
master
分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活 -
dev
分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本; -
每个人都在
dev
分支上干活,每个人都有自己的分支,时不时地往dev
分支上合并就可以了。
多人协作
多人协作的工作模式:
-
首先,可以试图用
git push origin <branch-name>
推送自己的修改; -
如果推送失败,则因为远程分支比你的本地更新,需要先用
git pull
试图合并; -
如果合并有冲突,则解决冲突,并在本地提交;
-
没有冲突或者解决掉冲突后,再用
git push origin <branch-name>
推送就能成功!
如果git pull
提示no tracking information
,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>
。
Git项目搭建
配置Git
#查看系统config
$ git config --system --list
#查看当前用户(global)配置
$ git config --global --list
#设置用户名和邮箱(必要)
$ git config --global user.name "Colin13" #名称
$ git config --global user.email 1002667204@qq.com #邮箱
创建本地仓库
#新建一个空目录并在目录下输入
$ git init
克隆远程仓库
#会克隆项目和整个代码历史(版本信息)
$ git clone https://gitee.com/kuangstudy/openclass.git
将文件添加到Git仓库
#首先需要在Git仓库文件夹中创建文件readme.txt
$ git add readme.txt #第一步:git add 将文件修改添加到暂存区
$ git commit -m "worte a readme file for testing" #第二步:git commit 将文件修改提交到当前分支,-m 后是对本次提交的说明,可以记录每次改动的信息
# 修正错误的commit
$ git commit -m 'new commit'
$ git commit --amend #重新提交:提交暂存区的文件,并用新的一次提交覆盖上一次的提交信息。
为什么添加到Git仓库要分成两步?
commit
可以一次提交多个文件,所以可以多次使用add
添加最后再用commit
统一提交
查看工作区状态及修改内容
#对readme.txt文件进行一些修改后
$ git status #查看工作区的状态,会提示文件被修改且未提交
$ git diff #查看修改内容
版本回退
$ git log #查看提交日志(顺序为从近到远)
#版本回退:
$ git reset --hard HEAD^ #将当前版本退回上一个版本(HEAD指针指向上一个版本)
#回退后再恢复:
$ git reflog #查看每一次历史修改的commit id(历史文件的版本号)
$ git reset --hard 1094a #恢复到1094a对应的版本
撤销修改
-
如果文件修改只在工作区内进行,未
add
到暂存区:
$ git checkout -- readme.txt #将readme.txt在工作区的修改全部撤销,--表示本分支
-
git checkout
:用版本库的版本替换工作区的版本 -
使用
git checkout -- readme.txt
撤销修改会有两种情况:-
readme.txt
在修改后还没有add
到暂存区,这时撤销修改会回到和版本库相同的状态 -
readme.txt
在add
到暂存区后又进行了修改,现在撤销修改会回到刚add
到暂存区的状态
-
-
谨慎使用这个命令,因为所有本地的修改都会丢失(git中只有已提交的才能恢复)
-
如果已经将文件修改并
add
到暂存区:
$ git reset HEAD readme.txt #将readme.txt退回工作区,此时暂存区被清空,工作区有修改
$ git checkout -- readme.txt #再用上文的命令撤销工作区的修改
删除文件
$ rm readme.txt #在工作区中删除文件(这一步也可以省略)
$ git rm readme.txt #将删除操作提交到暂存区
$ git restore --staged readme.txt #撤销提交到暂存区的删除操作,或
$ git commit -m "remove readme.txt" #将删除操作commit到版本库,彻底删除文件(无法找回)
只要删除操作没有被commit
到版本库,都可以通过git checkout
恢复到最新的版本
远程仓库
GitHub
-
在GitHub账户设置添加本地
.ssh
文件夹中的id_rsa.pub
公钥 -
GitHub新建仓库
-
上传本地仓库或创建新仓库,默认将远程库命名为
origin
本地仓库上传时出现
src refspec main does not match any
错误:本地仓库中没有文件,本地添加README
并commit
后再上传
添加远程仓库
$ git remote add <shortname> <url>
克隆远程库
自动将其添加为远程仓库并默认以 “origin” 为简写
默认情况下,git clone
命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master
分支(或其它名字的默认分支)。 运行 git pull
通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。
$ git clone git@github.com:michaelliao/gitskills.git
$ git pull
查看远程仓库信息
这个命令会列出远程仓库的 URL 与跟踪分支的信息,当你在特定的分支上执行 git push
会自动地推送到哪一个远程分支。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了, 还有当你执行 git pull
时哪些本地分支可以与它跟踪的远程分支自动合并。
# git remote show <remote>
$ git remote show origin
拉取某个仓库的数据
访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。
git fetch
命令只会将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。
# git fetch <shortname>
$ git fetch origin
推送本地更新
# git push <remote> <branch>
$ git push origin master #将本地master分支的最新修改推送至远程库
$ git push origin master:awesomebranch #将本地的master分支推送至远程库的awesomebranch分支
重命名远程仓库
修改远程仓库的简写名
# git remote rename <oldname> <newname>
$ git remote rename pb paul
移除远程库
(这里只是解绑,彻底删除库需要在GitHub网站上进行):
$ git remote -v #查看远程库信息
$ git remote rm origin #解除本地和远程的绑定关系(但不会删除远程库)
分支管理
创建与合并分支
# 创建分支
$ git branch dev #创建dev分支
$ git checkout -b dev #创建分支并切换到该分支,此后提交都在该分支上
# 查看分支
$ git branch #查看当前分支(列出所有分支,当前分支前会标*)
# 切换分支
$ git checkout master #切换回主分支
# 合并分支
$ git checkout master #先切换到想合并入的分支
$ git merge dev #将dev分支合并到主分支,默认为Fast forward策略
# 删除分支
$ git branch -d dev #删除dev分支
分支合并策略
无冲突的分支合并
fast-forward:当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧,这就叫做 “快进(fast-forward)”。
如果开发历史从一个更早的地方开始分叉开来(diverged)时,Git 会使用两个分支的末端所指的快照(C4
和 C5
)以及这两个分支的公共祖先(C2
),做一个简单的三方合并。
有冲突的分支合并
如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。此时 Git 做了合并,但是没有自动地创建一个新的合并提交。 Git 会暂停下来,等待你去解决合并产生的冲突。
$ git status #查看包含合并冲突而处于未合并(unmerged)状态的文件
任何因包含合并冲突而有待解决的文件,都会以未合并状态标识出来。 Git 会在有冲突的文件中加入标准的冲突解决标记,这样你可以打开这些包含冲突的文件然后手动解决冲突。
## 冲突文件示例 ##
## ======= 分隔两个版本的文件
<<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
## 可以将文件修改为下面这样以解决冲突
<div id="footer">
please contact us at support@github.com
</div>
或者也可以使用图形化工具来解决冲突
$ git mergetool
解决冲突后,重新将该文件添加到暂存区并commit即可
$ git add <filename>
分支管理策略
$ git branch #查看当前所有分支列表
$ git branch -v #查看每一个分支的最后一次提交
$ git branch --merged #查看哪些分支已经合并到当前分支
$ git branch --merged master #查看已合并到master的分支
$ git branch --no-merged #查看所有包含未合并工作的分支
$ git branch --no-merged master #查看尚未合并到master的分支
$ git branch -D test #强制删除test分支(包含未合并工作时-d删除会出错,要使用-D强制删除)
$ git log --oneline --decorate #查看各个分支当前所指的对象、提交记录
$ git log --oneline --decorate --graph --all #以图的形式查看提交历史、各个分支的指向以及项目的分支分叉情况。
$ git merge --no-ff -m "merge with no-ff" dev
#禁用Fastforward策略,以普通模式合并,因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。
不使用Fast forward
模式,merge
后会形成和解决冲突后相同的分支情况:
分支开发工作流
长期分支:在整个项目开发周期的不同阶段,你可以同时拥有多个开放的分支;你可以定期地把某些主题分支合并入其他分支中。
许多使用 Git 的开发者都喜欢使用这种方式来工作,比如只在 master
分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为 develop
或者 next
的平行分支,被用来做后续开发或者 测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master
分支了。 这样,在确保这些已完成的主题分支(短期分支,比如之前的 iss53
分支)能够通过所有测试,并且不会引入更多 bug 之后,就可以合并入主干分支中,等待下一次的发布。
稳定分支的指针总是在提交历史中落后一大截, 而前沿分支的指针往往比较靠前。
你可以用这种方法维护不同层次的稳定性。 一些大型项目还有一个 proposed
(建议) 或 pu: proposed updates
(建议更新)分支,它可能因包含一些不成熟的内容而不能进入 next
或者 master
分支。 这么做的 目的是使你的分支具有不同级别的稳定性;当它们具有一定程度的稳定性后,再把它们合并入具有更高级别稳定 性的分支中。 再次强调一下,使用多个长期分支的方法并非必要,但是这么做通常很有帮助,尤其是当你在一 个非常庞大或者复杂的项目中工作时。
远程分支
远程分支以<remote>/<branch>
的形式命名,如origin/master
,表示远程库origin上的master分支(origin是clone时git对远程服务器的默认命名,可以通过git clone -o <remote>
自定义)
克隆完成后本地会有master
和origin/master
两个指针
$ git ls-remote <remote> #显式获得远程引用的完整列表
$ git remote show <remote> #获得远程分支的更多信息
$ git remote add <shortname> <url> #添加新的远程仓库
当你想要公开分享一个分支时,需要将其推送到有写入权限的远程仓库上。本地的分支并不会自动与远程仓库同步——你必须显式地推送想要分享的分支。 这样,你就可以把不愿意分享的内容放到私人分支上,而将需要和别人协作的内容推送到公开分支。
跟踪分支
从一个远程跟踪分支检出一个本地分支会自动创建所谓的“跟踪分支”(它跟踪的分支叫做“上游分支”)。 跟踪分支是与远程分支有直接关系的本地分支。 如果在一个跟踪分支上输入 git pull
,Git 能自动地识别去哪个服务器上抓取、合并到哪个分支。
如果你尝试检出的分支不存在且刚好只有一个名字与之匹配的远程分支,那么 Git 就会为你创建一个跟踪分支
# 将本地分支设置为与上游分支不同的名字
$ git checkout -b sf origin/serverfix #本地创建一个和远程分支名字不同的跟踪分支
# 更改当前分支跟踪的上游分支
$ git branch -u origin/serverfix #设置跟踪的上游分支为origin/serverfix
$ git branch --set-upstream-to origin/serverfix #-u == --set-upstream-to
# 查看本地分支跟踪的远程分支,以及本地分支的版本情况🌟
$ git branch -vv #结果中的ahead表示本地未推送的提交,behind表示本地未拉取的提交
$ git fetch --all; git branch -vv #先抓取所有远程仓库,再查看
拉取
git fetch
命令从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容。 它只会获取数据然后让你自己合并。
git pull
在大多数情况下它的含义是一个 git fetch
紧接着一个 git merge
命令,会自动合并没有冲突的数据。如果有设置好的跟踪分支,git pull
都会查找当前分支所跟踪的服务器与分支, 从服务器上抓取数据然后尝试合并入那个远程分支。
由于 git pull
的魔法经常令人困惑所以通常单独显式地使用 fetch
与 merge
命令会更好一些。🌟
删除远程分支
# git push <remote> --delete <brench>
$ git push origin --delete serverfix #删除origin远程库的serverfix分支
这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。
处理bug分支(贮藏与清理)
$ git stash #stash可以将当前工作区储存在栈中,返回到上一个commit,在处理完bug后可以恢复;可以多次stash储存多个工作区状态
$ git checkout master #假设bug在master分支上
$ git switch -c issue-001 #在master上创建临时分支
#在issue-001上修复bug,修复完成后,切换回master分支,合并,删除issue-001分支
$ git stash list #查看保存工作区的栈的状态
-
有两种从栈中恢复工作区的方法:
#1
$ git stash apply stash@{0} #恢复指定的stash
$ git stash drop stash@{0} #删除指定的stash
#2
$ git stash pop #恢复stash的同时把stash内容也删除
-
复制其他分支的一个特定的提交到当前分支(例如:在master分支上修复的bug,想要合并到当前dev分支):
$ git branch
$ git cherry-pick 4c805e2 #cherry-pick+commitID 复制特定的提交到当前分支
Feature分支
-
开发一个新feature,最好新建一个分支;
-
如果要丢弃一个没有被合并过的分支,可以通过
git branch -D <name>
强行删除。
多人协作
$ git remote #查看远程库信息
$ git remote -v #查看远程库的详细信息
-
推送分支(分支是否推送可以自己决定):
$ git push origin master #将本地的master分支推送到远程库origin的对应远程分支上
-
抓取分支(从远程库clone时默认只会对
master
分支进行clone):
$ git checkout -b dev origin/dev #创建远程库origin的dev分支到本地
-
推送分支时发生冲突(两个人对同一个分支抓取修改,并先后推送;即其他人的最新提交和你当前提交有冲突):
$ git pull #解决方法:需要先用`git pull`把最新的提交从`origin/dev`抓下来,然后在本地合并,解决冲突,再推送
$ git branch --set-upstream-to=origin/dev dev #如果git pull失败,可能是由于没有指定本地dev分支与远程origin/dev分支的连接,此时需要设置链接再git pull
Rebase变基
Git 中整合来自不同分支的修改主要有两种方法:merge
以及 rebase
。
merge 在整合分支时,会把两个分支的最新快照(C3
和 C4
)以及二者最近的共同祖先(C2
)进行三方合并,合并的结果是生成一个新的快照(并提交)(C5
)。
rebase 提取在 C4
中引入的补丁和修改,然后在 C3
的基础上应用一次。 在 Git 中,这种操作就叫做 变基(rebase)。 你可以使用 rebase
命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。
# 检出 experiment 分支,然后将它变基到 master 分支上
$ git checkout experiment
$ git rebase master
变基的原理是首先找到这两个分支(即当前分支 experiment
、变基操作的目标基底分支 master
) 的最近共同祖先 C2
,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底 C3
, 最后以此将之前另存为临时文件的修改依序应用。
此后回到 master
分支,进行一次快进合并即可。
$ git checkout master
$ git merge experiment
两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。 你在查看一个经过变基的分支的历史记录时会发现,尽管实际的开发工作是并行的, 但它们看上去就像是串行的一样,提交历史是一条直线没有分叉。
一般我们这样做的目的是为了确保在向远程分支推送时能保持提交历史的整洁——例如向某个其他人维护的项目贡献代码时。 在这种情况下,你首先在自己的分支里进行开发,当开发完成时你需要先将你的代码变基到 origin/master
上,然后再向主项目提交修改。 这样的话,该项目的维护者就不再需要进行整合工作,只需要快进合并便可。
请注意,无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。
变基例子
创建了一个主题分支 server
,为服务端添加了一些功能,提交了 C3
和 C4
。 然后从 C3
上创建了主题分支 client
,为客户端添加了一些功能,提交了 C8
和 C9
。 最后,你回到 server
分支,又提交了 C10
。
取出 client 分支,找出它从 server 分支分歧之后的补丁, 然后把这些补丁在 master 分支上重放一遍,让 client 看起来像直接基于 master 修改一样
$ git rebase --onto master server client
快进合并 master
分支
$ git checkout master
$ git merge client
将 server 中的修改变基到 master 上
# git rebase <basebranch> <topicbranch>
$ git rebase master server
快进合并并删除分支
$ git checkout master
$ git merge server
$ git branch -d client
$ git branch -d server
最终提交历史记录:
变基的风险
奇妙的变基也并非完美无缺,要用它得遵守一条准则:如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。
变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。 如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 git rebase
命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。
如果团队中的某人强制推送并覆盖了一些你所基于的提交,你需要做的就是检查你做了哪些修改,以及他们覆盖了哪些修改。
如果有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交,如果我们不是执行合并,而是先 git fetch
,再执行 git rebase teamone/master
, Git 将会:
-
检查哪些提交是我们的分支上独有的
-
检查其中哪些提交不是合并操作的结果
-
检查哪些提交在对方覆盖更新时并没有被纳入目标分支
-
把查到的这些提交应用在
teamone/master
上面
关于变基和合并,总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。
标签管理
对版本(commit
)设置标签(标签实际上是不可移动的指针),方便管理
人们会使用这个功能来标记发布结点( v1.0
、 v2.0
等等)
Git 支持两种标签:轻量标签(lightweight)与附注标签(annotated)。
-
轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。
-
附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。 通常会建议创建附注标签,这样你可以拥有以上所有信息。但是如果你只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么也可以用轻量标签。
创建轻量标签
$ git switch master #切换到需要打标签的分支
$ git tag v1.0 #git tag <name>对分支设置标签
$ git tag #查看所有分支标签(按字母顺序排列)
$ git show v1.0 #查看标签信息
$ git tag -l "v1.8.5*" #查看所有v1.8.5开头的标签
$ git tag v0.9 f52c633 #对某次commit设置标签
$ git tag -a v0.1 -m "version 0.1 released" 1094abd #设置带有说明的标签,-a指定标签名,-m指定说明文字
-
注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。
操作标签
$ git tag -d v0.1 #删除标签
$ git push origin v1.0 #推送标签v1.0到远程库。创建的标签都只储存在本地,需要push才能推送到远程库
$ git push origin --tags #一次性推送全部尚未推送到远程库的本地标签
$ git tag -d v0.9 #如果标签已经推送到远程,要先从本地删除
$ git push origin :refs/tags/v0.9 #再从远程删除
GitHub使用
-
要参与GitHub的开源项目,要先将项目
Fork
到自己的账号,然后从自己的账号下clone
才能进行修改,否则没有权限 -
可以通过
pull request
向官方库推送自己的修改
提交准则
-
检查空白错误:
git diff --check
-
让每一个提交成为一个逻辑上的独立变更集,不要将解决的多个问题合并到一起提交
-
如果可以的话在提交前
-
规范地编写提交信息
-
一般情况下,信息应当以少于 50 个字符(25个汉字)的单行开始且简要地描述变更,接着是一个空白行,再接着是一个更详细的解释。
-
Git 项目要求一个更详细的解释,包括做改动的动机和它的实现与之前行为的对比。
-
使用指令式的语气来编写提交信息。
-
提交信息模版:
首字母大写的摘要(不多于 50 个字符)
如果必要的话,加入更详细的解释文字。在大概 72 个字符的时候换行。
在某些情形下,第一行被当作一封电子邮件的标题,剩下的文本作为正文。
分隔摘要与正文的空行是必须的(除非你完全省略正文),
如果你将两者混在一起,那么类似变基等工具无法正常工作。
使用指令式的语气来编写提交信息:使用“Fix bug”而非“Fixed bug”或“Fixes bug”。
此约定与 git merge 和 git revert 命令生成提交说明相同。
空行接着更进一步的段落。
- 标号也是可以的。
- 项目符号可以使用典型的连字符或星号,后跟一个空格,行之间用空行隔开,
但是可以依据不同的惯例有所不同。
- 使用悬挂式缩进
-
参与公开项目
向公开项目做贡献,一般需要遵循以下流程:
-
克隆主仓库,为计划贡献的补丁或补丁序列创建一个主题分支
featureA
,然后在那儿做工作。 -
当你的分支工作完成后准备将其贡献回维护者,去原始项目中然后点击“Fork”按钮,创建一份自己的可写的项目派生仓库。 然后需要在本地仓库中将该仓库添加为一个新的远程仓库
$ git remote add myfork <url>
-
将工作推送到你的派生仓库,通知原项目的维护者你有想要他们合并的工作。这通常被称作一个 拉取请求(Pull Request),你通常可以通过网站生成它,也可以运行
git request-pull
命令然后将随后的输出通过电子邮件手动发送给项目维护者。$ git push -u myfork featureA
$ git request-pull origin/master myfork
在一个你不是维护者的项目上,通常有一个总是跟踪 origin/master
的 master
分支会很方便,在主题分支上做工作是因为如果它们被拒绝时你可以轻松地丢弃。 如果同一时间主仓库移动了然后你的提交不再能干净地应用,那么使工作主题独立于主题分支也会使你变基(rebase)工作时更容易。
假设项目维护者已经拉取了一串其他补丁,然后才尝试拉取你的第一个分支,但是没有干净地合并。 在这种情况下,你可以尝试变基那个分支到 origin/master
的顶部,为维护者解决冲突,然后再重新提交你的改动。
$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA
如果此时维护者看到了你的第二个分支上的工作并且很喜欢其中的概念,但是想要你修改一下实现的细节。 你也可以利用这次机会将工作基于项目现在的 master
分支。 你从现在的 origin/master
分支开始一个新分支,在那儿压缩 featureB
的改动,解决任何冲突,改变实现,然后推送它为一个新分支。
$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
... change implementation ...
$ git commit
$ git push myfork featureBv2
--squash
选项接受被合并的分支上的所有工作,并将其压缩至一个变更集, 使仓库变成一个真正的合并发生的状态,而不会真的生成一个合并提交。 这意味着你的未来的提交将会只有一个父提交,并允许你引入另一个分支的所有改动, 然后在记录一个新提交前做更多的改动。
维护项目
-
在主题分支中工作,而不是主分支:如果你想向项目中整合一些新东西,最好将这些尝试局限在 主题分支——一种通常用来尝试新东西的临时分支中。 这样便于单独调整补丁,如果遇到无法正常工作的情况,可以先不用管,等到有时间的时候再来处理。 如果你基于你所尝试进行工作的特性为分支创建一个简单的名字,比如
ruby_client
或者具有类似描述性的其他名字,这样即使你必须暂时抛弃它,以后回来时也不会忘记。 项目的维护者一般还会为这些分支附带命名空间,比如sc/ruby_client
(其中sc
是贡献该项工作的人名称的简写)。 -
如果你的贡献者建立了自己的版本库,并且向其中推送了若干修改, 之后将版本库的 URL 和包含更改的远程分支发送给你,那么你可以将其添加为一个远程分支,并且在本地进行合并。
自定义Git
$ git config --global color.ui true #使Git显示颜色
忽略特殊文件
-
忽略某些文件时,需要编写
.gitignore
-
.gitignore
文件本身要放到版本库里,并且可以对.gitignore
做版本管理
配置Git
$ git config --global alias.st status #设置命令的别名,设置st来表示status
-
每个仓库的Git配置文件都放在
.git/config
文件中,而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig
中
搭建Git服务器
SourceTree
-
Git有很多图形界面工具,这里推荐
附录