Git 与 GitHub 操作简介
说明
此部分文档由张光耀同学撰写,本质上与R 无关。但是鉴于诸多R 包开发者都将其源代码托管于GitHub,因此,我们仍有必要了解这一社会化编程的工具与网站。文档中Git部分的技术性强一些,就GitHub的操作而言,会Fork别人的repo,会使用Pull Request和Merge Request,会使用Markdown进行写作,几乎就可以伪装成一只文科程序猿了。您不妨试试?
一
Git 与 Github 简介
GitHub 是为开发者提供 Git 仓库的托管服务,这是一个让开发者与朋友、同事、同学以及陌生人共享代码的平台。
GitHub 公司总部位于美国旧金山,拥有一只不知是章鱼还是猫的吉祥物 octocat 。
GitHub 和 Git 的区别在于,在后者中,开发者将文件放入 Git 仓库中加以使用,前者是在互联网上提供 Git 仓库的一项服务。GitHub 上公开的代码全部由 Git 进行管理,也就是说,理解 Git 是熟练操作 GitHub 的关键。
Git 最初由 Linux kernel 的作者 Toevalds 先生研发,是用来管理 Linux kernel 项目的工具。它的功能是负责项目的版本控制,我们称之为“版本控制系统”(Version Control System, VCS)。Git 相比之前的版本控制系统,有诸多优点,可以提高团队开发的效率,避免在文档修改时破坏文档。因此有“后来者居上”的态势。
每一个操作系统都会找到适合自己的 Git 安装程序,下面是官方网站的下载地址:http://git-scm.com/downloads
按照下图的指导进行安装:
此时在开始菜单中可以看到 Git 的安装文件夹,其中有三个程序,分别是 Git Bash 、Git GUI 、Git CMD 。我们需要了解的是前两者。其中 Git GUI 属于鼠标操作的程序,具有良好的用户体验和操作界面。Git Bash 属于基本的操作程序,需要使用者手动编写程序。建议初学者先学习 Git Bash,这样可以了解其工作细节,再切换到 Git GUI 时,自然水到渠成。鉴于 Git Bash 的功能十分强大,本文只对其进行简单的介绍。
1.Git Bash
打开 Git Bash 会看到以下的界面
界面上的内容含义如下。$后面就是命令输入的区域。
用户名称@计算机名称文件夹路径(当前分支)
初始要输入用户名和邮箱,命令如下,读者可根据自己的喜好自行选择,但是建议和 GitHub 设为同一邮箱。
设置完成后,可以开始进行文件管理了。这里注意,虽然不设置用户名和邮箱,下面的部分操作也可以进行,但是无法对文件的修改进行标记,更为复杂的内容也无法进行。
- 管理文件
管理文件,首先要选择要操作的文件夹。有两种方式,可以直接在文件夹中右键鼠标,点击Git Bash here,也可以在 Bash 程序中执行如下的命令,达到的效果是一样的。
cd ‘文件夹路径’
接下来执行git into,让 Git 开始管理这个文件夹。执行完后 Git 出现相应信息Initialized empty repository in 文件夹路径/.git/,表示已经完成准备工作。
下面我们在文件夹中新建文本文档,取名为array.txt,在里面输入下面的内容:
完成并储存后关闭文档,Bash 中执行命令git add array.txt,接着输入命令git status即可查看当前的工作状态,可以看到以下信息:
结果显示,有一个名叫array.txt的文件被送到文件库里面。下面将文件送入文档库中,要执行git commit命令,该命令格式如下:
git commit -m '这次操作的说明' --author='操作者姓名' <email邮箱>
由于我们已经设定了邮箱和操作者,因此不用在此设定了,直接执行下面的命令:
git commit -m 'add array.txt
完成后,array.txt文件已经被加载到文件库中,接下来我们对该文件进行修改,将33333改为44444,更改后的内容如下:
回到 Git Bash 中,执行下面的操作,把修改后的文件加载到文档库中。
下面执行gitk启动图片查看模式,这样就可以查看当前文档库里的文件了。
左上角会有不同颜色的节点,每一个节点表示执行过一次git commit指令。节点右边会显示我们输入的操作说明。
左下角的窗口会显示当前节点的完整信息,节点最上面会有一个master标签,表示这是文件的“主要分支”(master branch)。
节点会按照时间顺序从上往下排列,最上面的节点表示最近一次的 commit ,最下面的节点表示最初的 commit 。
节点窗口右边的两个窗口分别显示执行指令的人和时间。
右下角的窗口是当前选定的 commit 节点的内容,它有两种查看模式:patch 和 tree 。patch 模式会显示和前一个 commit 节点的差异,tree 模式则显示完整的节点内容,左边的窗口会显示它的内容。比如选择最近一次的节点,用 patch 模式查看,会显示下面的内容:
可以看出第三行原来的33333被删除,之后又增加了44444一行。
- 控制 commit
如果我们执行了git add命令后反悔了,例如加错文件,这个时候必须删除加入 git 索引的文件内容。要执行这种操作分两种情况:没有执行过git commit和执行过git commit。
如果是第一种情况,直接执行下面命令即可:
git rm --catch 文件名
其中--catch可不加,加上表示从此以后不需要在文档库中更新这个文件,也就是这个文件将会被改为不被追踪的状态。
我们已经学会如何用gitk来查看 commit 节点,每一个节点都有先后顺序关系,比如array.txt文档的两个节点。系统会赋予每个节点独一无二的标签,以此标识。Git 还提供了一种叫做 HEAD 的节点标签,这个节点标签永远表示最新的 commit 节点,例如我们可以输入命令git show HEAD来显示最新 commit 的详细数据。而 HEAD 上面的节点的标签遵循HEAD^ <数字>的格式。HEAD 上一层的节点标签为 HEAD^1 ,上两层的节点标签为 HEAD^2 ,以此类推。
因此,如果已经执行过commit命令,想删除文件,需执行下面的命令:
git reset 选项 <commit 节点标识符或标签>
其中的选项如果是--soft,表示只有文档库中的数据会改变,Git 索引和文件夹中的文件都不会受到影响。如果是--mixed(这是默认选项),表示 Git 索引也会恢复到指定节点的状态,但是文件夹中的文件仍然不会受到影响。如果选项是--hard,则文档库,Git索引和文件夹中的文件,都会恢复到指定节点的状态。
除了 Git 内设的 HEAD 节点标签之外,我们也可以自己帮 commit 节点“贴上”自定义的标签,指令如下:
git tag <自定义的标签名称> <commit 节点标识符或标签>
将 commit 节点贴上标签后,就可以像 HEAD 标签一样使用自定义的标签了。
如果想删除自定义的标签,可以使用命令:
git tag –d <已自定义的节点或标签>
- Git Bash 文件的差异比较,取回和索引
除了用gitk观察文件的差异,Git 也为我们提供了如下的指令:
git diff <commit 节点标识符或标签> <commit 节点标识符或标签>
比如我们执行命令git diff HEAD^1 HEAD,就会显示最新节点和上一个节点array.txt文件的差别,如下所示:
这里注意,节点的顺序不同结果不同,因此命令git diff HEAD HEAD^1会产生和上面不同的结果,如下所示:
除了比较差异,因为每一个 commit 标签都是独一无二的,因此我们可以通过标签找回文档,这比较简单,只需要借助命令git checkout即可,它的格式如下:
git checkout <commit 节点标识符或标签>
例如我们的例子中,我想回到最初的版本,即33333没有被44444取代,可以执行命令git checkout HEAD^1。但要注意命令执行后最新的节点将变成想要恢复的节点,换句话说,最新的版本将会失去,文件夹中的文件会被取出的文件覆盖。
如果我们想要找出包含某一个字符串的文件,这时候可以使用git grep指令,它的格式如下:
git grep '要找的字符串' <commit 节点>
Git 会搜索指定的 commit 节点中的所有文件,然后列出包含该字符串的每一行。如果没有制定 commit 节点,表示要搜索文件夹中所有的文件。如果要找的字符串不止一个,可以试着用-e选项分别指定这些字符串:
git grep -e ‘要找的字符串1’ -e ‘要找的字符串2‘ <commit 节点>
这种方式默认以 or 方式连接,如果要限制所有的字符串都必须出现才算数,可以用--and选项把它们结合起来如下:
git grep -e '要找的字符串1' --and -e '要找的字符串2' <commit 节点>
Git 提供了修改文件名的指令git mv,它的用法如下:
git mv <原来的文件名> <新文件名>
要暂存文件夹中的文件状态可以使用git stash save指令,这个指令会执行下面两项工作:
-
储存文件夹中被 Git 追踪的文件和文档库中最新的文件版本的差异;
-
把文件夹中被 Git 追踪的文件还原成文档库中最新的文件版本。
这项功能可以让我们把当前文件中的“文件修改状态”暂存起来。以便稍后回复,例如当程序修改到一半的时候,突然收到一个临时性的工作,需要先修改其他地方。当前的工作只进行到一半,不适合将它存入文档库,这时候就可以使用暂存功能,先将当前的文件状态记录下来,然后开始处理临时的工作,等到临时工作处理完毕之后,再将文件夹中的文件恢复到原来的状态。
Git 文档库经过一段时间的存取和更改之后,里面的数据可能会变得比较零散,有些数据不会再使用,这虽然不会影响 Git 的正常运行,但是会降低 Git 效率,而且浪费磁盘的空间,因此我们需要清理 Git 文档库。
清理文档库其实很容易,只需要执行git gc指令即可,(gc 是 garbage collection 的缩写),它有一些搭配的选项如下:
-
--aggressive:Git 在默认的情况下,会比较快速的检查文档库,并完成清理,如果加入这个选项,Git 会用比较仔细的方式检查以及清理,但是需要比较久的时间,这个选项只需要“偶尔”使用即可,太常使用会浪费时间,不会有明显的帮助。
-
--auto:如果加入这个选项,Git 会先判断文档库中是都需要清理,如果情况还算好,就会执行清理操作。
-
--no-prune:这个选项是要求 Git 不要清除文档库中不会用到的数据,只要整理他们即可。
- Git Bash 分支的创建和合并
我们之前的操作都是在 master 分支上进行的,Git 中提供了创建分支和合并分支的指令,这为修改代码提供了方便。接下来我们演示分支的创建。
首先创建一个新文件夹,将 Git 的工作路径设置到该文件夹。创建新文本文档poem1.txt,输入下面内容:
执行下面命令:
执行下面命令创建新分支:
git branch lee-by
接下来在文件夹中创建新的文本文档poem2.txt,内容如下:
回到 Git Bash 程序,注意,虽然已经创建新分支,但是目前还是在 master 分支上修改文件,因此下面的操作还是将文档加载到 master 分支上。
其中git add .命令是添加所有文件到 Git 索引,已经被索引的不会被重复添加。
在文件夹中新增poem3.txt文件,内容如下:
回到 Git Bash 程序,执行以下命令,完毕后,会在 lee-by 分支上增加一个 commit 节点,并且新增poem3.txt文件。
执行完后,打开文件夹,发现其中只有poem1.txt和poem3.txt两个文件,这是因为我们当前的分支 lee-by 上只加载了这两个文件,如果执行git checkout master,再打开文件夹,发现有poem1.txt和poem2.txt两个文件,因为这两个文件是 master 分支上的。
这里需要注意,poem1.txt是在创建分支前就添加到 master 分支的,因此之后创建的分支 lee-by 会自动继承这个文件,但是poem2.txt是在分支创建之后才添加到 master 分支上的,因此新的分支不会继承。
接下来我们执行下面的命令,完成合并。
因为要将分支合并,因此先切回到主要分支上,再将 lee-by 分支合并。其中 git merge 是分支合并指令,它的用法如下:
git merge <分支名称>
这样,我们可以看到,本来不属于 master 分支的poem3.txt也被添加到 master 分支了。
接下来我们执行命令 gitk –all 就可以看到完整的节点演进图(仅执行gitk只能查看当前分支的节点演进图)。可以看到,在最新的节点处,两个分支合二为一;在最初的节点后,分成两个分支。
接下来我们回到合并之前的情况,了解一下当合并发生冲突时该如何处理。
执行命令git reset --hard HEAD~1回到合并之前的情景。
执行git checkout master将路径转移到 master 分支上。
打开poem1.txt,添加下面两行内容:
执行下面命令:
接下来, 执行git checkout lee-by。
打开poem1.txt,此时的poem1.txt依然是以前的内容,添加下面两行内容:
执行下面的命令:
此时两个分支中的poem1.txt已经储存着不同的内容。执行下面的命令:
结果如下:
表明不能自动合并,因为两个poem1.txt的内容有冲突。在这种情况下,需要我们人为地解决冲突。
打开poem1.txt文件,其内容如下所示,在有冲突的地方有标识。
我们需要处理好这些冲突,然后删除标识符,再执行下面的命令就可以完成合并了。
在上面两种情况下完成合并后,如果分支不再需要,则可删除分支,删除分支的命令如下:
git branch -d <要删除的分支名称>
注意,如果要删除分支,必须先切换到另一分支上。在一般情况下,分支应该合并到另一个上,如果要删除的分支还没有合并,Git 会显示错误信息,并且停止删除分支的操作。如果确定要删除分支,可以把上面指令中的-d改为-D,要求 Git 强制删除该分支。
如果想要改变分支的名称,就必须先切换到该分支,然后执行以下命令:
git branch -m <新分支的名称>
执行合并后,master 分支和 develop 分支又会出现更新,反复合并后打开节点演进图,会看到左边所示的图。虽然这样并不影响程序的正常运行,但是网状结构过于复杂,不利于辨认,因此我们可以通过rebase命令,避免两个分支形成相互交织的情况,让程序项目的 commit 节点演进图变得比较简单,而且容易理解。
使用命令时只要把merge换成rebase就可以,如下:
和merge一样,rebase也会出现发生冲突的情况,在 Bash 中也会出现错误地报告,但是不同的是,出现报告后我们仍处在rebase的状态中,因此需要决定是否放弃这一次合并。如果放弃,可执行git rebase --abort命令;如果要继续合并,就要自己编辑发生冲突的文件,接着执行以下命令完成rebase操作:
如果在执行rebase时发生冲突,我们可以通过git rebase –abort命令放弃rebase;但是如果rebase已经从头到尾执行完毕了,此时想恢复到rebase以前的状态,我们可以使用git reset命令,但是必须要找到相应的节点标签。
Git 中提供了查找借点历史记录的命令:
git reflog <HEAD 或任何分支的名称>
如果执行git reflog时不加任何参数,会列出 HEAD 变动的历史记录,假设某个情境下我们执行git reflog时,结果如下:
执行下面命令就可以回到rebase之前的状态:
git reset –hard HEAD@{3}
2. Git GUI
Create New Repository
单击这个选项后,会让我们输入一个文件夹路径,程序会在这个指定的文件夹路径创建一个 Git 文档库。如果已经在文件夹中右键,那么只需输入文件夹的名字即可。这个操作相当于 Git Bash 中的git init。
Clone Existing Repository
这个选项用来复制一个已经存在的程序项目和它的的 Git 文档库。选择这个以后,会让我们输入程序项目的文件夹路径和要复制过去的文件夹路径。
Open Existing Repository
选择这个选项后,会让我们输入一个文件夹路径,里面是已经创建好的 Git 文档库。Git GUI 程序会切换到这个文件夹,然后开始运行。这个选项相当于 Git Bash 中的cd指令一样。Git 程序会自动读取 Git 文档库的状态。
左上方区域会显示当前程序项目文件夹内有哪些文件在加入到 Git 文档库后又被修改了,以及有哪些文件处于untracked的状态。
右上方的区域显示的是点选的文件状态和内容。
左下方的区域是显示当前已经加入到 Git 索引的文件。我们可以使用右边的Stage Change按钮,把左上方区域显示的文件加到 Git 索引中。
右下方的区域包含操作按钮和执行commit时输入的操作说明。
-
Stage Change:将文件添加到 Git 索引中
-
Rescan:重新扫描文件夹中的文件,更新文件的状态
-
Commit:进行 commit 说明
另外,单击Stage Changed按钮时,程序会先检查文件夹中是否有untracked状态的文件。如果有,就会显示对话框,询问是否要把untracked的文件登录到 Git 索引中。
-
如果选择“是”,程序会把所有untracked的文件、被修改的文件和被删除的文件全部登录到 Git 索引中,这就等于在 Git Bash 中执行git add -A命令。
-
如果选择“否”,程序只会把修改的文件和被删除的文件登录到 Git 索引。这就等于 Git Bash 程序中执行git add -u指令。
除了Stage Changed按钮,也可以单击左边区域的文件名前面的小图标来实现相同的功能。如果想加入某几个文件,可以配合键盘的 Shift 和 Ctrl 键,先选好文件,然后选择主菜单的Commit > Stage To Commit。如果要从 Git 索引中删除某些文件,同样选好文件,再选择主菜单的Commit > Unstage From Commit。
使用 Git GUI 同样可以创建和合并分支。
首先创建一个文本文档file.txt,自行输入内容。点击Rescan,按照上文介绍将file.txt文件加入到文档库中。
在右下方空白区域输入add file.txt,点击 commit 按钮。完成主要分支的建立。
点击主菜单的Branch > Create,显示下图所示的画面。
在Name一栏中输入名称,例如develop,最下面的选项Checkout After Creation表示创建完分支后会自动切换到该分支,默认是选上的。如果点击取消后,稍后可通过主菜单Branch > Checkout完成切换。
切换到 develop 分支后,打开文件夹,创建新的文本文档file2.txt,自行输入内容,然后打开file.txt,自行添加一些内容,保存。接下来把新建的file2.txt和修改后的file.txt添加到 Git 文档库中。此时新分支上新增了一个文件,并且原来的文件也被修改。
接下来执行合并分支操作。
切换到 master 分支上 点击主菜单 Merge > Local Merge,会出现下图所示画面:
空白处显示当前的其他分支,选取你要合并的分支,比如我们选取 develop 分支,然后点击“merge”,完成合并。合并过程也可能会产生冲突,此时我们可以有两种解决方法:一是放弃合并,点击主菜单“Merge > Abort Merge”;一是自行解决冲突,可以点击主菜单的“Repository > Git Bash”,启动Git Bash,然后按照我们之前说的那样解决冲突。
可以看出,虽然 Git GUI 的界面更友好,操作更简洁,它依然是依附于 Git Bash 的软件,无法具有后者那样的强大功能。
3. GitHub 介绍
GitHub 官网网址是 https://github.com/
使用 GitHub 需要自行申请账号(无需翻墙!无需缴费!无需担心!)。创建之初,页面会显示出两个选项Read the guide和Start a project,读者可点击前者详细阅读如何创建登录新文档,如何创建和合并分支,如何发布新文档。因为前面已经对 Git Bash 有了基础的了解。
Read the guide网址:https://guides.github.com/activities/hello-world/
GitHub 的重点不在于操作文档,而在于交流文档。前面提到过,这是一个平台,在网页的最上面有一个 search 的区域,读者可以搜索自己感兴趣的代码库,比如输入 Java ,会查到很多关于 Java 的代码。
我们可以选取一个自己感兴趣的代码库进入,进入后在右上方有 Watch 选项,利用 Watch ,读者可以选择追踪这个代码库,一旦库有更新,就可以收到通知。同样,读者点击任何一个代码,会进入下图所示的编辑页面,点击右边的笔状图标即可开始编辑。编辑完成后,填写页面最下面的 Propose file change ,点击 Propose file change ,就可以发布了。发布完成后,系统会发送邮件反馈修改的结果。
二
在 R 中使用 GitHub
通过 GitHub 建立版本库后,在 R 中也可以使用 GitHub 。
打开 RStudio ,点击 File ,选择 New Project ,选择 Version Control ,选择 Git。
需要填写一些基本信息:
-
URL:你的 Git 版本库的 HTTPS 地址。
-
project directory name:可以创建一个本地文件夹。
-
Create as a subdirectory of:选择上述文件夹放在本地的路径。
找到上述版本库所存储的本地路径。
如果是 R 相关的文件,你可以用 RStudio 打开,进行修改编辑。
2.在 RStudio 中确认修改并上传
右上角方块中选择 Git (如果你修改过文档,文档会出现在其中),点击Commit(可添加简要说明),点击Push上传(需要用到你的账号和密码)即可。
冲突的解决和分支的合并在 GitHub 客户端或者网页端解决即可。R 中不提供此功能。
- 本文固定链接: https://maimengkong.com/morejc/818.html
- 转载请注明: : 萌小白 2021年12月25日 于 卖萌控的博客 发表
- 百度已收录