Pro Git 笔记
1. 起步
1. 3种版本控制系统(VCS:Version Control Systems)
(1)本地版本控制系统
主要有: rcs
缺点: 开发者不能协同工作
(2)集中化的版本控制系统 ( CVCS: Centralized Version Control Systems)
主要有: CVS,Subversion, Perforce
缺点: 中央服务器如果发生单点故障,将会是一个灾难
(3)分布式版本控制系统( DVCS: Distributed Version Control System)
主要有: Git,Mercurial,Bazaar 以及 Darcs
优点:任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。
2. 哈希值作索引
在保存到 Git 之前,所有数据都要进行内容的校验和(checksum)计算,并将此结果作为数据的唯一标识和索引。Git 使用 SHA-1 算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个 SHA-1 哈希值,作为指纹字符串。实际上,所有保存在 Git 数据库中的东西都是用此哈希值来作索引的,而不是靠文件名。
3. 文件的三种状态
对于任何一个文件,在 Git 内都只有三种状态:已修改(modified),已暂存(staged),已提交(committed)。
Git 管理项目时,文件流转的三个工作区域:工作目录,暂存区域,以及本地仓库(Git 目录)。
Git 目录: 如果 git clone
出来的话,就是其中 .git
的目录;如果 git clone --bare
的话,新建的目录本身就是 Git 目录。它是 Git 用来保存元数据和对象数据库的地方。
工作目录: 从项目中取出某个版本的所有文件和目录,用以开始后续工作的叫做工作目录。这些文件实际上都是从 Git 目录中的压缩对象数据库中提取出来的,接下来就可以在工作目录中对这些文件进行编辑。
暂存区域: 是个简单的文件,一般都放在 Git 目录中。有时候人们会把这个文件叫做索引文件.
基本的 Git 工作流程如下:
- 在工作目录中修改某些文件。
- 对修改后的文件进行快照,然后保存到暂存区域。
- 提交更新,将保存在暂存区域的文件快照永久转储到 Git 目录中。
4. 初次运行 Git 前的配置
Git 提供了一个叫做 git config 的工具(译注:实际是 git-config
命令,只不过可以通过 git
加一个名字来呼叫此命令。),专门用来配置或读取相应的工作环境变量。
这些变量可以存放在以下三个不同的地方:
/etc/gitconfig
文件:系统中对所有用户都普遍适用的配置。若使用git config
时用--system
选项,读写的就是这个文件。/etc/gitconfig
文件,是在 Git 安装目录下。~/.gitconfig
文件:用户目录下的配置文件,只适用于该用户。若使用git config
时用--global
选项,读写的就是这个文件。- 当前项目的 git 目录中的配置文件(也就是工作目录中的
.git/config
文件):这里的配置仅仅针对当前项目有效。每一个级别的配置都会覆盖上层的相同配置,所以.git/config
里的配置会覆盖/etc/gitconfig
中的同名变量。
安装 Windows 版Git 后,一般要使用 C:\Program Files (x86)\Git\Git Bash 来对Git进行操作。Git Bash是一个Linux命令行工具。比如
~/.gitconfig
文件,在Git Bash中输入用户的主目录”~“,即 $HOME
变量指定的目录,在Win7下,一般都是 C:\Users\$USER
。比如在Git Bash中输入
u124612@PEK124612D01 /etc $ cd ~ u124612@PEK124612D01 ~ $ pwd /c/Users/user123
(1)用户信息
第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录。
$ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com
(2)文本编辑器
Git默认会使用操作系统指定的默认编辑器,一般可能会是 Vi 或者 Vim。在Windows下,你可以设置为记事本:
$ git config --global core.editor C:/Windows/SysWOW64/notepad.exe
注意:
一定要使用斜杠方式:core.editor = C:/Windows/SysWOW64/notepad.exe,不要使用 C:\Windows\SysWOW64\notepad.exe,即使加了转义符:C:\\Windows\\SysWOW64\\notepad.exe,也不对。
如果使用了后者,当使用后面的git rm命令时,你会发现会出现错误:
$ git commit C:\Windows\SysWOW64\notepad.exe: line 1: C:WindowsSysWOW64notepad.exe: command not found error: There was a problem with the editor 'C:\Windows\SysWOW64\notepad.exe'. Please supply the message using either -m or -F option.
(3)差异分析工具
在解决合并冲突时使用哪种差异分析工具。Git 可以理解 kdiff3,tkdiff,meld,xxdiff,emerge,vimdiff,gvimdiff,ecmerge,和 opendiff 等合并工具的输出信息。
改为vimdiff的话:
$ git config --global merge.tool vimdiff
修改完后,C:\Users\u123\.gitconfig 文件变成了如下的样子:
[user] name = ZhangSan email = johndoe@example.com [core] editor = C:\\windows\\notepad.exe [merge] tool = vimdiff
本来想改为Beyond Compare 3,但是Git不认这个工具。汇报如下的错误:
$ git mergetool git config option merge.tool set to unknown tool: C:/Program Files (x86)/Beyond Compare 3/BCompare.exe Resetting to default... This message is displayed because 'merge.tool' is not configured. See 'git mergetool --tool-help' or 'git help config' for more details. 'git mergetool' will now attempt to use one of the following tools: tortoisemerge emerge vimdiff No files need merging
(4)查看配置信息
要检查已有的配置信息,可以使用 git config --list
命令。它会先列出/etc/gitconfig的配置,然后~/.gitconfig的配置。
有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig
和~/.gitconfig
),不过最终 Git 实际采用的是最后一个。
u124612@PEK124612D01 ~ $ git config --list core.symlinks=false core.autocrlf=input color.diff=auto color.status=auto color.branch=auto color.interactive=true pack.packsizelimit=2g help.format=html http.sslcainfo=/bin/curl-ca-bundle.crt sendemail.smtpserver=/bin/msmtp.exe diff.astextplain.textconv=astextplain rebase.autosquash=true user.name=ZhangSan user.email=johndoe@example.com core.editor=C:\windows\notepad.exe merge.tool=C:\Program Files (x86)\Beyond Compare 3\BCompare.exe
也可以直接查阅某个环境变量的设定,只要把特定的名字跟在后面即可,像这样:
$ git config user.name
ZhangSan
2. Git基础
1. 取得项目的 Git 仓库
(1)在工作目录中初始化新仓库
要对现有的某个项目开始用 Git 管理,只需到此项目所在的目录
$ git init 初始化后,在当前目录下会出现一个名为 .git 的目录
$ git add *.c $ git add README $ git commit -m 'initial project version'
(2)从现有仓库克隆
用 git clone
命令,是与与Subversion的checkout 相对应的命令
比如,要克隆 Ruby 语言的 Git 代码仓库 Grit,可以用下面的命令:
$ git clone git://github.com/schacon/grit.git 这会在当前目录下创建一个名为grit的目录,其中包含一个 .git 的目录,用于保存下载下来的所有版本记录,然后从中取出最新版本的文件拷贝。 如果希望在克隆的时候,自己定义要新建的项目目录名称,可以在上面的命令末尾指定新的名字,唯一的差别就是,现在新建的目录成了 mygrit。 $ git clone git://github.com/schacon/grit.git mygrit
Git 支持许多数据传输协议。之前的例子使用的是 git://
协议,不过你也可以用 http(s)://
或者user@server:/path.git
表示的 SSH 传输协议。
2. 文件的状态变化过程
3. 基础操作:
$ git status
检查当前文件状态
$ git add README
git add是个多功能命令,根据目标文件的状态不同,此命令的效果也不同:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等
$ git add --all
添加当前目录下的所有文件和子文件夹。
$ git diff
此命令比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来(没有git add)的变化内容。
$ git diff --cached
看已经暂存起来的文件(经过git add)和上次提交时的快照之间的差异。(Git 1.6.1 及更高版本还允许使用 git diff --staged
,效果是相同的,但更好记些)
$ git commit
一定要确认还有什么修改过的或新建的文件还没有 git add
过,否则git commit 的时候不会记录这些还没暂存起来(git add)的变化。所以,每次准备提交前,先用 git status
看下,是不是都已暂存起来了,然后再运行提交命令 git commit。
提交时记录的是放在暂存区域的快照,任何还未暂存的仍然保持已修改状态,可以在下次提交时纳入版本管理。
$ git commit -m "commit for test"
可以用 -m 参数后跟提交说明的方式,在一行命令中提交更新:
$ git commit -a -m 'added new benchmarks'
-a 会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add
步骤
$ git rm
从已跟踪文件清单中移除,并连带从工作目录中删除指定的文件。
$ git rm -f :如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f (即 force 的首字母)
$ git rm --cached readme.txt
移除跟踪但不删除文件。
$ git mv file_from file_to
对文件改名。运行 git mv
就相当于运行了下面三条命令:
$ mv README.txt README $ git rm README.txt $ git add README
4. $ git log: 查看提交历史
(1)默认不用任何参数的话,
git log
会按提交时间列出所有的更新,最近的更新排在最上面。每次更新都有一个 SHA-1 校验和、作者的名字和电子邮件地址、提交时间,最后缩进一个段落显示提交说明。
$ git log -p -2
-p
选项展开显示每次提交的内容差异,用 -2
则仅显示最近的两次更新
$ git log -U1 --word-diff
将行层面的对比,改为单词层面的对比。新增加的单词被 {+ +}
括起来,被删除的单词被 [- -]
括起来: s.version = [-"0.1.0"-]{+"0.1.1"+}
在进行单词层面的对比的时候,你可能希望上下文( context )行数从默认的 3 行,减为 1 行,那么可以使用 -U1
选项。
$ git log --stat
git log
还提供了许多摘要选项可以用,其中, --stat
,仅显示简要的增改行数统计。
$ git log --pretty=oneline
--pretty
选项,可以指定使用完全不同于默认格式的方式展示提交历史。比如
oneline
将每个提交放在一行显示,这在提交数很大时非常有用。另外还有
short 仅显示每次提交的提交说明。
full
显示作者和提交者
fuller 显示作者和提交者,以及作者创建日期和提交日期。
作者(author)和提交者(committer)之间究竟有何差别,其实作者指的是实际作出修改的人,提交者指的是最后将此工作成果提交到仓库的人。所以,当你为某个项目发布补丁,然后某个核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。
format
,可以定制要显示的记录格式,这样的输出便于后期编程提取分析
$ git log --pretty=format:"%h - %an, %ar : %s"
下表列出了常用的格式占位符写法及其代表的意义。
选项 | 说明 |
---|---|
%H |
提交对象(commit)的完整哈希字串 |
%h |
提交对象的简短哈希字串 |
%T |
树对象(tree)的完整哈希字串 |
%t |
树对象的简短哈希字串 |
%P |
父对象(parent)的完整哈希字串 |
%p |
父对象的简短哈希字串 |
%an |
作者(author)的名字 |
%ae |
作者的电子邮件地址 |
%ad |
作者修订日期(可以用 -date= 选项定制格式) |
%ar |
作者修订日期,按多久以前的方式显示 |
%cn |
提交者(committer)的名字 |
%ce |
提交者的电子邮件地址 |
%cd |
提交日期 |
%cr |
提交日期,按多久以前的方式显示 |
%s |
提交说明 |
$ git log --pretty=format:"%h %s" --graph
形象地展示每个提交所在的分支及其分化衍合情况。
$ git log --since=2.weeks
列出所有最近两周内的提交。 你可以给出各种时间格式,比如说具体的某一天(“2008-01-15”),或者是多久以前(“2 years 1 day 3 minutes ago”)。
$ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" --before="2008-11-01" --no-merges -- t/
查看 Git 仓库中,2008 年 10 月期间,Junio Hamano 提交的但未合并的测试脚本(位于项目的 t/ 目录下的文件)
(2)gitk: 图形化工具查阅提交历史
随 Git 一同发布的 gitk 工具。在项目工作目录中输入 gitk 命令后,就会启动gitk工具。
5. 撤销操作
(1)$ git commit --amend
修改最后一次提交。有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了,使用该命令,如果刚才提交完没有作任何改动,相当于有机会重新编辑提交说明,但将要提交的文件快照和之前的一样。执行该命令后会启动文本编辑器,会看到上次的提交的说明,编辑后保存退出,就会使用新的提交说明覆盖刚才失误的提交。
如果刚才提交时忘了暂存某些修改(没有git add),可以先补上暂存操作,然后再运行 --amend 提交:
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
上面的三条命令最终只是产生一个提交,第二个提交命令修正了第一个的提交内容。
(2)如果README.txt,benchmarks.rb 二者一起被git add,全加到了暂存区域,但是想要分来暂存,如何撤消暂存其中的一个文件呢?
$ git reset HEAD benchmarks.rb
取消已经暂存的文件,让其回到了之前未暂存的状态。
(3)如果觉得刚才对 benchmarks.rb 的修改完全没有必要,该如何取消修改,回到之前的状态(也就是修改之前的版本)呢?
$ git checkout -- benchmarks.rb
取消修改,恢复到修改前的版本。
6. 远程仓库的使用
(1)查看当前的远程库
$ git remote
它会列出每个远程库的简短名字。在克隆完某个项目后,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库
$ git remote -v
-v
选项(此为 --verbose
的简写,取首字母),显示对应的克隆地址。
(2)添加远程仓库: git remote add [shortname] [url]
$ git remote add pb git://github.com/paulboone/ticgit.git
(3)从远程仓库抓取数据:
$ git fetch [remote-name]
此命令会到远程仓库中拉取所有你本地仓库中还没有的数据。运行完成后,你就可以在本地访问该远程仓库中的所有分支,将其中某个分支合并到本地。
如果是克隆了一个仓库,此命令会自动将远程仓库归于 origin 名下。所以,git fetch origin
会抓取从你上次克隆以来别人上传到此远程仓库中的所有更新(或是上次 fetch 以来别人提交的更新)。有一点很重要,需要记住,fetch 命令只是将远端的数据拉到本地仓库,并不自动合并到当前工作分支,只有当你确实准备好了,才能手工合并。
$ git pull
如果设置了某个分支用于跟踪某个远端仓库的分支,可以使用 git pull
命令自动抓取数据下来,然后将远端分支自动合并到本地仓库中当前分支。实际上,默认情况下 git clone
命令本质上就是自动创建了本地的 master 分支用于跟踪远程仓库中的 master 分支(假设远程仓库确实有 master 分支)。所以一般我们运行 git pull
,目的都是要从原始克隆的远端仓库中抓取数据后,合并到工作目录中的当前分支。
(4)推送数据到远程仓库: git push [remote-name] [branch-name]
$ git push origin master
把本地的 master 分支推送到origin
服务器上。如果在你推数据前,已经有其他人推送了若干更新,那你的推送操作就会被驳回。你必须先把他们的更新抓取到本地,合并到自己的项目中,然后才可以再次推送。
(5)查看远程仓库信息: git remote show [remote-name]
$ git remote show origin
查看所克隆的 origin
仓库的信息
(6)远程仓库的删除和重命名
$ git remote rename pb paul
修改某个远程仓库在本地的简称,把 pb
改成paul。
$ git remote rm paul
移除对应的远端仓库(碰到远端仓库服务器迁移,或者原来的克隆镜像不再使用,又或者某个参与者不再贡献代码)。
3. Git分支
1. 分支管理,切换
$ git branch
git branch
命令不仅仅能创建和删除分支,如果不加任何参数,它会给出当前所有分支的清单。
$ git branch iss53 * master testing
注意看 master
分支前的 *
字符:它表示当前所在的分支。也就是说,如果现在提交更新,master
分支将随着开发进度前移。
git branch -v
查看各个分支最后一个提交对象的信息
git branch --merged
查看哪些分支已被并入当前分支(译注:也就是说哪些分支是当前分支的直接上游。)
git branch --no-merged
查看尚未合并的分支。由于这些分支中还包含着尚未合并进来的工作成果,所以简单地用 git branch -d
删除该分支会提示错误,因为那样做会丢失数据。不过,如果你确实想要删除该分支上的改动,可以用大写的删除选项 -D
(git branch -D
)强制执行。
$ git branch testing
在当前 commit 对象上新建一个 testing 分支。
$ git checkout testing
切换到新建的 testing 分支。Git 是如何知道你当前在哪个分支上工作的呢?它保存着一个名为 HEAD 的特别指针,它是一个指向你正在工作中的本地分支的指针(译注:将 HEAD 想象为当前分支的别名。)。运行 git branch
命令,仅仅是建立了一个新的分支,但不会自动切换到这个分支中去,执行 git checkout
命令后,HEAD 就指向了 testing 分支。
$ git checkout master
切换回master分支。HEAD 就又指向了 master分支。
$ git checkout -b iss53
这相当于执行下面这两条命令(新建分支,并切换到新建的分支):
$ git branch iss53
$ git checkout iss53
$ git merge hotfix : 合并hotfix分支。
Fast forward:
若合并时出现了“Fast forward”的提示,是由于当前 master
分支所在的提交对象是要并入的 hotfix
分支的直接上游,Git 只需把 master
分支指针直接右移。换句话说,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,因为这种单线的历史分支不存在任何需要解决的分歧,所以这种合并过程可以称为快进(Fast forward)。
遇到冲突时的分支合并:
先使用 log status 看看哪些文件在合并时发生冲突。任何包含未解决冲突的文件都会以未合并(unmerged)的状态列出。在解决了所有文件里的所有冲突后,运行 git add
将把它们标记为已解决状态(译注:实际上就是来一次快照保存到暂存区域。)
$ git branch -d hotfix
-d
选项执行删除操作。
2. 远程分支
用 (远程仓库名)/(分支名)
这样的形式表示远程分支。
举例:假设你们团队有个地址为 git.ourcompany.com
的 Git 服务器。如果你从这里克隆,Git 会自动为你将此远程仓库命名为 origin
,并下载其中所有的数据,建立一个指向它的master
分支的指针,在本地命名为 origin/master(--这就是远程分支)。
但你无法在本地更改其数据。接着,Git 建立一个属于你自己的本地 master
分支,始于 origin
上 master
分支相同的位置,你可以就此开始工作。
如下图:一次 Git 克隆会建立你自己的本地分支 master 和远程分支 origin/master,并且将它们都指向origin
上的 master
分支。
可以运行 git fetch origin
来同步远程服务器上的数据到本地,他会把把origin/master
的指针移到它最新的位置上。
假设别人又新建了一个远程分支 serverfix
,并且想push到服务器origin仓库上。push的方法是:
$ git push origin serverfix
也可以运行 git push origin serverfix:serverfix
来实现相同的效果,它的意思是“上传我本地的 serverfix 分支到远程仓库中去,仍旧称它为 serverfix 分支”。
通过此语法,也可以把本地分支推送到某个命名不同的远程分支:若想把远程分支叫作 awesomebranch
,可以用 git push origin serverfix:awesomebranch
来推送数据。
那么你如何获得这个别人新建的远程分支serverfix呢?
你在本地从服务器上$ git fetch origin 获取数据时,将得到一个新的远程分支 origin/serverfix,但是你仍然无法在本地编辑该远程仓库中的serverfix分支。因为$ git fetch origin 操作不会为你创建一个新的
serverfix
分支,你有的只是一个无法移动的origin/serverfix
远程分支指针(在克隆仓库时,Git 通常会自动创建一个名为 master
的本地分支来跟踪 origin/master
。这正是 git push
和 git pull
一开始就能正常工作的原因)。接下来你有2种选择:
(1)把该远程分支的内容合并到当前分支: 可以运行 git merge origin/serverfix
。
(2)如果想要一份自己的 serverfix
分支来开发,可以在远程分支的基础上分化出一个新的分支来: $ git checkout -b serverfix origin/serverfix (1.6.2 以上版本的 Git,还可以用
--track
选项简化:$ git checkout --track origin/serverfix)
这会切换到新建的 serverfix
本地分支,其内容同远程分支 origin/serverfix
一致,这样你就可以在里面继续开发了。从远程分支 checkout
出来的本地分支,称为 跟踪分支 (tracking branch)。serverfix
分支就是一个跟踪分支。
删除远程分支:
$ git push origin :serverfix
有种方便记忆这条命令的方法:记住我们不久前见过的 git push [远程名] [本地分支]:[远程分支]
语法,如果省略 [本地分支]
,那就等于是在说“在这里提取空白然后把它变成[远程分支]
”。
3. 衍合(rebase:重定基底)分支
把一个分支中的修改整合到另一个分支的办法有两种:merge
和 rebase
简单的衍合例子:
(1)初始状态
(2)采用merge操作的话:
(3)采用rebase操作的话:
a)切换到 experiment 分支,然后以master分支为基底rebase (即rebase master操作),这样,experiment分支的各个补丁文件,就逐个移到了master分支里面(这里只有一个C3'):
$ git checkout experiment
$ git rebase master
我们可以直接把 experiment 分支衍合到 master
,而不用手工切换到 experiment 分支后再执行衍合操作。方法就是:git rebase [主分支] [特性分支]
。该命令会先取出特性分支 experiment,然后在主分支 master
上重演:
$ git rebase master experiment
b)然后回到 master
分支,进行一次快进合并。
$ git checkout master
$ git merge experiment
c)现在experiment 分支的变化都已经集成到主干分支来了,可以删掉 experiment 分支了。
$ git branch -d experiment
(4)结果
衍合的 C3' 对应的快照,其实和普通的三方合并,即merge 例子中的 C5 对应的快照内容一模一样。这两者都会得到相同的快照内容,只不过提交历史不同罢了。衍合是按照每行的修改次序重演一遍修改,而合并是把最终结果合在一起。
衍合的风险:
在进行衍合的时候,实际上抛弃了一些现存的提交对象而创造了一些类似但不同的新的提交对象。如果你把原来分支中的提交对象发布出去,并且其他人更新下载后在其基础上开展工作,而稍后你又用 git rebase
抛弃这些提交对象,把新的重演后的提交对象发布出去的话,你的合作者就不得不重新合并他们的工作,这样当你再次从他们那里获取内容时,提交历史就会变得一团糟。
衍合的原则:
一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。
如果把衍合当成一种在推送之前清理提交历史的手段,而且仅仅衍合那些尚未公开的提交对象,就没问题。
4. 服务器上的Git
主要介绍GitHub上相关操作
1. 如何在GitHub上托管项目?
在GitHub上Create Repository:
参照: https://help.github.com/articles/creating-a-new-repository 的步骤。
创建的Repository名字为:ZhchnchnTest,注意这个名字,后面会用到。选择自动添加 .gitignore, 选择 C++语言, GitHub会自动为你创建一个 .gitignore文件。
然后,就是本地操作了。
可参照: https://help.github.com/articles/create-a-repo 的步骤
(1)在E:\GitHub\ 下创建 ZhchnchnTest目录
(2)$ cd /E/GitHub/ZhchnchnTest/
(3)$ git init
Initialized empty Git repository in e:/GitHub/ZhchnchnTest/.git/
(4)用VS2010创建一个空的 Solution,复制该Solution文件 ZhchnchnTest.sln 到 e:/GitHub/ZhchnchnTest 目录
(5)添加文件到git repository
$ git add ZhchnchnTest.sln
(6)提交
$ git commit -m 'First commit'
(7)然后在这个本地仓库内把 GitHub 添加为远程仓库,并推送 master 分支上来
添加远程仓库:
$ git remote add origin https://github.com/zhchnchn/ZhchnchnTest.git
注意这个名字是前面GitHub上创建Repository时的名字,并且是大小写敏感的,一定要保持一致。这个时候,本地的Git仓库就和远程的GitHub服务器联系起来了。
(8)推送数据到远程仓库:
$ git push origin master
它会让你输入GitHub的用户名密码,输入用户名密码后,回车提交,这时会报错:
To https://github.com/zhchnchn/ZhchnchnTest.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'https://github.com/zhchnchn/ZhchnchnTest.git ' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first merge the remote changes (e.g., hint: 'git pull') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
错误的原因是:GitHub中有一些work你本地并没有,所以会拒绝你提交。回想一下,GitHub有什么work我们本地没有呢?是在创建Repository时自动添加的README和.gitignore文件。
(9)所以,先从GitHub同步work到本地来。有2种办法:
a)$ git pull origin master
b)先fetch,再merge
$ git fetch origin
$ git merge origin/master
(19)然后,再次 $ git push origin master。这次会提交成功。现在该项目就托管在 GitHub 上了。
2. 如何删除一个Repository?
https://help.github.com/articles/deleting-a-repository
5. 分布式Git
1. 分布式工作流程
(1)集中式工作流
适用于:团队不是很大
第二个开发者在提交他的修订之前,必须先下载合并服务器上的数据,解决冲突之后才能推送数据到共享服务器上。就好比是在用 Subversion(或其他 CVCS)一样,可以很好地工作。如果提交代码时有冲突, Git 根本就不会让用户覆盖他人代码,它直接驳回第二个人的提交操作。这就等于告诉提交者,你必须先拉取最新数据下来,手工解决冲突合并后,才能继续推送新的提交。
(2)集成管理员工作流
有个代表着官方发布的项目仓库(blessed repository),开发者们由此仓库克隆出一个自己的公共仓库(developer public),然后将自己的提交推送上去,请求官方仓库的维护者拉取更新合并到主项目。维护者在自己的本地也有个克隆仓库(integration manager),他可以将你的公共仓库作为远程仓库添加进来,经过测试无误后合并到主干分支,然后再推送到官方仓库。工作流程看起来就像图 所示:
a) 项目维护者可以推送数据到公共仓库 blessed repository。
b) 贡献者克隆此仓库,修订或编写新代码。
c) 贡献者推送数据到自己的公共仓库 developer public。
d) 贡献者给维护者发送邮件,请求拉取自己的最新修订。
e) 维护者在自己本地的 integration manger 仓库中,将贡献者的仓库加为远程仓库,合并更新并做测试。
f) 维护者将合并后的更新推送到主仓库 blessed repository。
在 GitHub 网站上使用得最多的就是这种工作流: 人们可以复制(fork 亦即克隆)某个项目到自己的列表中,成为自己的公共仓库。随后将自己的更新提交到这个仓库,所有人都可以看到你的每次更新。这么做最主要的优点在于,你可以按照自己的节奏继续工作,而不必等待维护者处理你提交的更新;而维护者也可以按照自己的节奏,任何时候都可以过来处理接纳你的贡献
(3)司令官与副官工作流
这其实是上一种"集成管理员工作流"的变体。一般超大型的项目才会用到这样的工作方式。各个集成管理员分别负责集成项目中的特定部分,所以称为副官(lieutenant)。而所有这些集成管理员头上还有一位负责统筹的总集成管理员,称为司令官(dictator)。司令官维护的仓库用于提供所有协作者拉取最新集成的项目代码。整个流程看起来如图所示:
a) 一般的开发者在自己的特性分支上工作,并不定期地根据主干分支(dictator 上的 master)衍合。
b) 副官(lieutenant)将普通开发者的特性分支合并到自己的 master 分支中。
c) 司令官(dictator)将所有副官的 master 分支并入自己的 master 分支。
d) 司令官(dictator)将集成后的 master 分支推送到共享仓库 blessed repository 中,以便所有其他开发者以此为基础进行衍合。
2. 提交指南
一份好的提交指南可以帮助协作者更轻松更有效地配合
(1)不要在更新中提交多余的白字符(whitespace)。
Git 有种检查此类问题的方法,在提交之前,先运行 git diff --check,会把可能的多余白字符修正列出来
(2)将每次提交限定于完成一次逻辑功能
(3)撰写提交说明
6. Git工具
N/A
7. 自定义Git
1. 配置合并与比较工具P4Merge
书上给出的是Linux下的配置例子,下面是在Windows上的配置步骤:
(1)下载P4Merge:
http://www.perforce.com/downloads,我选择的是 “Free 20-User Edition”,点击进入后,http://www.perforce.com/downloads/Perforce/20-User
在该页面下方,找到 “P4Merge: Visual Merge Tool”,选择操作系统 WIndows, 版本 x64,然后下载。
下载后得到一个 “p4vinst64.exe” 文件。
(2) 安装
注意安装包中包含4个组件,安装过程中,注意只安装 P4Merge 和 Command-Line Client 这2个。其余两个Disable。
安装完成后,在安装目录下会有一个p4merge.exe 文件。
(3)配置
参考: http://idas643.blog.163.com/blog/static/167104838201387262685/
http://www.geekgumbo.com/2010/05/12/installing-and-using-p4merge-in-git-for-windows/
安装目录自动添加到了环境变量Path里面: C:\Program Files\Perforce。(NOTE: even if p4merge is added to your PATH on install, a restart is needed for git bash to recognize the change)
所以下面 ~/.gitconfig 的修改,你不必担心p4merge的安装路径问题。
vim ~/.gitconfig,编辑完后,保存该文件,重启git bash。
(4)测试
测试diff方法:
(a)修改一个repository中的文件,先不git add提交,
(b)运行 git diff,可在git bash里 查看有哪些修改,
(c)运行 git difftool,可启动P4Merge来可视化观察。
测试merge方法:
(a)远程修改一个GitHub repository中的文件,提交。
(b)然后在本地repository中修改同一个文件。
(c)然后,git pull origin master 获取远程repository中的提交。
(d)然后,git merge origin/master 合并,这时会提示你本地有一个修改还未提交,merge前需要先提交该修改。
$ git merge origin/master
Updating fafbb10..175871d
error: Your local changes to the following files would be overwritten by merge:
README.md
Please, commit your changes or stash them before you can merge.
(e)然后,提交修改 git add README.ad, 然后提交暂存, git commit -m "commit for merge",提交成功。
(f)然后,再次合并git merge origin/master ,这时会提示你自动合并失败。需要你解决冲突后再提交。
$ git merge origin/master Auto-merging README.md CONFLICT (content): Merge conflict in README.md Automatic merge failed; fix conflicts and then commit the result.
(g)然后,git mergetool 启动P4Merge,
P4Merge上半部分显示3个窗口:
$BASE file, 未修改之前的内容
$LOCAL file, 在local repository 修改的内容
$REMOTE file, 在remote repository (GitHub)修改的内容
P4Merge下半部分显示1个窗口:
$MERGED file, 显示合并后的结果。可以在此窗口中对冲突的部分进行手工合并,关闭P4Merge前记得一定要保存。
(h)然后,git commit 提交合并后的文件,这时能够提交成功了。
(g)然后, git push origin master,将修改push到GitHub服务器上去。
2. 配置格式化与空白
(1)格式化 core.autocrlf
$ git config --global core.autocrlf true
如果是在Windows系统上,把它设置成true,Git可以在你提交时自动地把行结束符CRLF转换成LF,而在签出代码时把LF转换成CRLF。
$ git config --global core.autocrlf input
Linux或Mac系统使用LF作为行结束符,因此你不想 Git 在签出文件时进行自动的转换.把core.autocrlf设置成input来告诉 Git 在提交时把CRLF转换成LF,签出时不转换。这样会在Windows系统上的签出文件中保留CRLF,会在Mac和Linux系统上,包括仓库中保留LF。
$ git config --global core.autocrlf false
如果你是Windows程序员,且正在开发仅运行在Windows上的项目,可以设置false取消此功能,把回车符记录在库中:
(2)空白 core.whitespace
Git预先设置了一些选项来探测和修正空白问题, 有4种主要选项
2个选项是默认被打开的: trailing-space会查找每行结尾的空格,space-before-tab会查找每行开头的制表符前的空格。
2个选项是默认被关闭的:indent-with-non-tab会查找8个以上空格(非制表符)开头的行,cr-at-eol让 Git 知道行尾回车符是合法的。
$ git config --global core.whitespace trailing-space,space-before-tab,indent-with-non-tab
设置core.whitespace,按照你的意图来打开或关闭选项,选项以逗号分割。通过逗号分割的链中去掉选项或在选项前加-来关闭,打开除了cr-at-eol之外的所有选项.
8. Git与其他系统
n/a
9. Git内部原理
n/a
References:
【1】ProGit (http://git-scm.com/book/zh)