第 3 章 CI和git

导读:结合个人的常用git操作场景,梳理和总结了常用版本控制技巧,便于随时翻看和使用。

一些有用的自学材料:

Pro git book(Scott Chacon and Ben Straub)

3.1 git配置

配置默认文本编辑器(text editor)。windows党还是自觉使用Notepad吧,免费又熟悉

  • 下载安装Notepad++(默认安装路径)

  • 打开GitBash,并输入如下代码

$ git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"

配置合并检查工具(mergetool)。这个必须要图形化GUI的,p4merge就是一个不错的选择。

  • 下载并安装p4merge。默认安装路径为"C:Program Files\Perforce\p4merge.exe"

  • 打开GitBash,并输入如下代码:

$ git config --global diff.tool p4merge
$ git config --global difftool.p4merge.path 'C:\Program Files\Perforce\p4merge.exe'

$ git config --global merge.tool p4merge
$ git config --global mergetool.p4merge.path 'C:\Program Files\Perforce\p4merge.exe'

3.1.1 安装git bash

此步骤必须

  • 下载git bash到本地电脑

  • 在本地电脑安装git bash——强烈建议默认安装路径

3.1.2 申请github账号

,高校邮箱有福利(可以建立私有仓库啊,完成你的秘密项目)。

记得取一个简单好记的用户名;记得改一个有个性的头像。(后面协作开发项目的时候,可以更方便沟通和交流!)。

  • Git Bash窗口,并输入如下代码(这是告诉git,我将以如下身份开始git之旅啦!):
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

3.1.3 安装文本编辑器Notepad++

此步骤非必须,根据个人爱好而定。

配置默认文本编辑器(text editor)。windows党还是自觉使用Notepad吧,免费又熟悉

  • 下载并在本地电脑安装Notepad++——强烈建议默认安装路径

  • Git Bash窗口,并输入如下代码(这是告诉git,我将使用如下的默认文本编辑器):

$ git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"

3.1.4 安装并配置合并检查工具——p4merge

此步骤非必须,看你是不是git重度用户。

配置合并检查工具(mergetool)。这个必须要图形化GUI的,p4merge就是一个不错的选择。

  • 下载并在本地电脑安装p4merge。————强烈建议默认安装路径

windowns系统下默认安装路径一般为"C:Program Files\Perforce\p4merge.exe"

  • Git Bash窗口,并输入如下代码(这是告诉git,我将使用如下的合并检查工具):
$ git config --global diff.tool p4merge
$ git config --global difftool.p4merge.path 'C:\Program Files\Perforce\p4merge.exe'

$ git config --global merge.tool p4merge
$ git config --global mergetool.p4merge.path 'C:\Program Files\Perforce\p4merge.exe'

3.1.5 检查git配置信息

如果上述步骤都做好了,你可以系统地检查一下是不是git配置都正确(如你所愿)啦!

  • Git Bash窗口,并输入如下代码(这是告诉git,请列出我所有的git配置信息):
$ git config --list

经验法则:如果git操作中,出现了merge conflict,则需要用到p4merge进行冲突解决。

$ git mergetool

3.2 git常用命令

3.2.1 git界面命令

  1. 如何查看git工作目录?在Git Bash窗口,输入并运行如下代码:
pwd
  1. 如何退出当前列表?在Git Bash窗口,输入并运行代码q,可以直接退出当前的列表ls

  2. 如何退出Git Bash窗口?在Git Bash窗口,输入并运行代码exit,可以直接退出git Bash窗口

3.2.2 git查看提交历史

视图化查看提交历史、各个分支的指向以及项目的分支分叉情况:

$ git log --oneline --decorate --graph --all

或者简略查看历史提交记录:

git log --pretty=oneline

3.2.3 git文件及文件夹命令

  1. cd: change directory的简写,改变目录的意思,就是切换到哪个目录下, 如 cd e:切换 E 盘下面的fff 目录。

  2. cd ..: 回退到上一个目录。我们在写js,引入文件时,.. 表示的就是上一个目录, 所以 cd .. 回退到上一个目录就很好理解了。注意,cd 和两个点点..之间有一个空格,

  3. pwd: print working directory, 打印工作目录,它会显示我们当前所在的目录路径。

  4. ls: list, 列出当前目录中的所有文件, 只不过ll(两个ll)列出的内容更为详细。

  5. touch: 新建一个文件如 touch index.js就会在当前目录下新建一个index.js文件。

  6. rm: remove,删除一个文件, rm index.js 就会把index.js文件删除.

  7. mkdir: make directory 新建一个目录,就是新建一个文件夹. 如mkdir src 新建src 文件夹.

  8. rm -r : 删除一个文件夹, r (recusive 是递归的意思), 删除用的就是递归,先删除文件夹里面的内容,再删除文件夹。 rm -r src 删除src目录。

  9. mv 移动文件, mv index.html src index.html 是我们要移动的文件, src 是目标文件夹,当然, 这样写,必须保证文件和目标文件夹在同一目录下.

  10. reset 清屏,把git bash命令窗口中的所有内容清空。

  11. exit 可以直接退出窗口。

3.3 git仓库管理

3.3.1 基于本地项目创建

  1. 准备本地电脑上的工作文件夹。例如,在d盘新建一个名为project的文件夹,那么工作文件路径就是d:/project/

工作文件夹最好不要设在系统盘,如c盘。——系统重装可能就麻烦了!

文件夹命名不要出现中文。——编程世界中还是乖乖用英语吧!

  1. Git Bash窗口,并输入如下代码(这是告诉git,请进入工作文件夹吧):
git cd /d/project

3.3.2 基于Rstudio的本地项目创建

基本操作:

  • 全新创建本地项目:Rstudio \(\Rightarrow\) File \(\Rightarrow\) New Project \(\Rightarrow\) New Directory

  • 打开刚才创建的R project(xxx.Rproj),此时可以使用Rstudio自带的Terminal进行git指令操作。

  • git初始化,完成第一次提交

# 初始化
$ git init -b main
# 添加变动
$ git add .
# 备注变动
$ git commit -m "First commit"
  • 登陆你的github,并创建一个空的远程仓库repo(操作略,注意不要勾选添加任何文件,如gitignore类型或readme!)。并复制仓库地址(例如:git@github.com:user/your-repo.git

  • 将本地项目添加并推送到刚才创建的远程github仓库:

# 添加到远程仓库
$ git remote add origin git@github.com:user/your-repo.git

# 当然也可以随时删除
$ git remote rm origin

# 检查并确认
$ git remote -v

# 推送到远程仓库
$git push --set-upstream origin main

3.3.3 克隆(clone)在线仓库

如果你想学习并改进一个已经github在线的公开项目,你可以把它克隆下来:

  1. 在github网站上找到自己喜欢的在线仓库,例如:https://github.com/huhuaping/team-students

  2. Git Bash窗口,并输入如下代码(这是告诉git,请拷贝这个在线仓库吧):

git clone https://github.com/huhuaping/team-students
  1. 上述操作会在当前工作目录下创建一个名为 “team-students” 的目录,并在这个目录下初始化一个 .git 文件夹。

3.3.4 派生(fork)仓库

如果你想对一个公开项目(例如,https://github.com/huhuaping/team-students )做出自己的贡献,你可以把它fork到你的github账户下。

  1. 进入github官方网站,用你的账号密码登陆进去。

  2. 在浏览器上新建标签页,找到你感兴趣的公开项目(例如,https://github.com/huhuaping/team-students )。

你也可以直接搜索你感兴趣的任意公开项目

  1. 对于这个你感兴趣的公开项目,点击网页上大大的Fork按钮。

  2. 这时,你可以在你自己账户下的仓库列表中,看到刚才Fork的你感兴趣的项目。

  3. Git Bash窗口,并输入如下代码(这是告诉git,请进入工作文件夹吧):

git clone https://github.com/your-account-name/team-students

注意:这里的your-account-name是你github账户的用户名——因为你把别人的公开项目(派生)Fork到自己的账户下啦!

  1. 进入工作文件夹。在Git Bash窗口,并输入如下代码(这是告诉git,请进入工作文件夹吧):
cd  /d/projects/team-students
  1. 新建一个名为git-intro分支(branch),并检出(checkout)到这个分支。——这一步的意义以后再说吧。在Git Bash窗口,并输入如下代码(这是告诉git,请进入工作文件夹吧):
git checkout -b git-intro

3.3.5 项目仓库版本控制

  1. 对项目代码进行修改和完善。例如,

打开R项目文件team-students.Rproj,运行Rstudio 修改其中Rmarkdown文件02-git-team-intro.Rmd的内容,例如增加一行代码。 保存(save)好修改。

  1. 暂存(stage)修改。在Git Bash窗口,并输入如下代码(这是告诉git,把这个文件暂存stage起来吧):
git add 02-git-team-intro.Rmd
  1. 提交(commit)修改。在Git Bash窗口,并输入如下代码(这是告诉git,提交修改,并附注一条信息add a new line):
git commit -m 'add a new line'
  1. 推送(push)修改。在Git Bash窗口,并输入如下代码(这是告诉git,把我们的修改推送到github云端去吧):
git git push origin git-intro

3.4 git分支操作

3.4.1 推送本地新建分支

参考

  1. 新建并检出到本地分支(local branch)
$ git checkout -b dev
  Switched to a new branch 'dev'
  1. 查看远程分支(remotes)
$ git remote -v
  1. 设定上游分支(upstream),以后就可直接推送:语法为git push -u <remote> <branch>
$ git push -u origin feat
$ git push
  1. 查看上游分支的引用关系
$ git branch -avv

3.4.2 合并分支branch

$ git checkout master
$ git merge hotfix

3.4.3 修改分支名称

缘起:历史上github默认的主分支为master,而目前则默认主分支为main

相关操作可参看

# 修改本地分支名称
$ git branch -m master main

# 修改远端分支
$ git push -u origin main

# 修改默认设置分支(此步骤也可登陆github账号进行设置)
$ git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main

# 删除旧的远端分支
$ git push origin --delete master

3.4.4 删除本地分支

$ git branch -d branch_name
$ git branch -D branch_name

参看队长问答How do I delete a Git branch locally and remotely?

3.4.5 删除远程分支

$ git push <remote_name> --delete <branch_name>
$ git push <remote_name> :<branch_name>

说明remote_name一般为origin

参看队长问答How do I delete a Git branch locally and remotely?

3.4.6 无法把本地repo推送到远程repo

这种情形下,直接push会提示如下报错:

git error: failed to push some refs to 'https://github.com/

问题可能有多个:

  • 没有进行远程设置。可以通过如下代码查看是否进行了远程设置。
# 正常情况下显示结果如下:
$git remote -v
myOrigin ssh://git@example.com:1234/myRepo.git (fetch)
myOrigin ssh://git@example.com:1234/myRepo.git (push)


# 否则就应该进行远程设置:
$git remote add origin ssh://git@example.com:1234/myRepo.git
  • 然后再进行推送:
# origin是远端,master是本地分支
$git push origin master
# 报错信息
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:huhuaping/netlify.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
# 同步远端和本地
$ git pull origin master

# 如果显示冲突conflict,则利用合并工具处理
$ git mergetool

3.4.7 分支push找不到上游分支

如果是本地新建分支,则需要设定上游分支,否则push就会报错:

# 报错信息。
$ git push
fatal: The current branch dev has no upstream branch.
To push the current branch and set the remote as upstream, use

处理办法是:

$ git push --set-upstream origin dev

3.4.8 回到远端状态

回到远端状态(例如,本地已提交,但是push提示合并冲突时,想把本地pull为远端状态)。参看队长问答

git reset --hard origin/<your branch>

如果要撤回到到指定的过往提交(commit)点,则使用命名:

git reset --hard origin/<your branch> e75862c

3.4.9 放弃本地的修改(未提交)

参看队长问答.

#删除remove所有untracked files
git clean -df

#清除clear 所有untracked files
git checkout -- .

#保存痕迹
git stash save --keep-index --include-untracked

# 不保存痕迹
git stash save --keep-index

3.4.10 删除已提交记录中的文件并添加到ignore列表

Rstudio默认会添加一些排除文件给.gitignore(合理的),但是如果用户之前就已经在远端repo上提交过这些排除文件,那么就可能会出现一个烦人的情形:每次打开Rstudio,terminal下使用git status检查就会提示.Rproj.user/shared/notebooks/paths

处理办法就是要彻底在远端先删除这些应该给排除的文件。这样以后才能彻底安心。具体可参看队长问答

First of all your files are already committed so you have to remove it from the repo:

# Once you add files to git, it will keep tracking them,  
# so we have to delete them and commit your deletion
git rm -r --cached .Rproj.user/**

# Commit the deleted files
git commit -m "Removed files...."

# now add it to the `.gitignore` and the files will be ignored
echo '.Rproj.user/**' > .gitignore

注意:其中最后一步echo可以手动操作,避免错误删除之前正确设定的ignore清单列表!

3.5 git忽略文件

3.5.1 配置文件

工作思路是:

  • 在工作目录下新建.gitigore文件
$ touch .gitignore
  • git bash调用文本编辑工具(windows死粉的notepad++),编辑并设置.gitignore文件
# 配置notepad(64bit system -windows)
$ alias notepad="/c/Program\ Files\ \(x86\)/Notepad++/notepad++.exe"

# 打开编辑器,设置忽略规则
$ notepad .gitignore
  • 忽略规则的一个样例
# ignore the whole file directory

data-raw/

# ignore Rproj user info file

.Rproj.user

3.5.2 忽略文件无效及处理办法

有时候.gitignore里虽然进行了修改设定,但并不会马上生效。

此时,问题可能就出在缓存上(cash)(参看My .gitignore file is ignored by git and it does not work,或者参看Gitignore is not Working)。

解决办法是清理缓存-提交:

$ git rm -r --cached .
$ git add .
$ git commit -m "Untracked files issue resolved to fix .gitignore"

场景实例:(两台设备上)git操作时反复出现.Rproj.user/shared/notebooks/paths

处理办法(参考):

# Once you add files to git, it will keep tracking them,  
# so we have to delete them and commit your deletion
git rm -r --cached .Rproj.user/**

# Commit the deleted files
git commit -m "Removed files...."

# now add it to the `.gitignore` and the files will be ignored
echo '.Rproj.user/**' > .gitignore

要点:**表示文件夹。

3.6 github文件超越容量限制

3.6.1 LFS安装和设定

经验法则:如果项目库中存在大于50M以上单个文件需要上传到github,则应提前设定了LFS,然后再push,否则可能会出现LFS与git(多次提交)之间的冲突,而导致push失败。

挑战的问题:git bash 命令push时,如果单个文件大于50M以上,则会提示推送失败。

参考的解决办法包括:

实际的解决办法为:

# git bash下确认是否成功安装

$ git lfs install
> Git LFS initialized.
# 追踪大容量文件所在的文件夹
$ git lfs track "data-process/"
  • 提交并推送LFS
# 添加所有改动文件夹
$ git add .

# 提交并推送
$ git commit -m "add LFS directory data-process/"
$ git push origin master
  • 查看所有设定的LFS文件列表
$ git lfs ls-files --all

3.6.2 LFS记录冲突报错的处理

经验法则:LFS指针回滚,与git commit的指针回滚,不是同一个概念。操作的时候要慎重决定LFS回滚数量n的确定。

如果出现了LFS记录冲突报错,具体原因一般是:git push之前忽视了大文档的存在,然后后面再进行LFS设定。这时,git 多次的commit提交,就会与LFS记录针头产生冲突(即便亡羊补牢后面进行了LFS设定)。此时,git push具体报错信息如下:

# 具体报错信息
remote: error: GH001: Large files detected.
remote: error: Trace: f22735321d76092fa67a1011835dfdcc
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File mySDK.framework/mySDK is 185.09 MB; this exceeds GitHub's file size limit of 100.00 MB
To git@github.com:company/repo.git
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'git@github.com:company/repo.git'

当然,我们也是有办法先将LFS记录文档从git 仓库中先移除(可参看Remove git-lfs from Repository)。具体步骤如下:

  • 步骤1:移除LFS工具,git命令为$ git lfs uninstall

  • 步骤2:把LFS记录从仓库中清除,git命令为$ git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch *.psd' HEAD~18..HEAD

  • 步骤3:提交到远端。git命令为$ git push

注意

  • *.psd为待移除的LFS文件,可以使用regex表达式;

  • HEAD~18..HEAD是从之前的n条commit记录中清除关于LFS的设定,在这里n=18,具体以个人的实际git commit情况而定。

3.7 github帐号添加SSH key

许多 Git 服务器都使用SSH公钥进行认证。为了向Git服务器提供SSH公钥,如果某系统用户尚未拥有密钥,必须事先为其生成一份。简单说,如果本地电脑采用SSH key来与服务器对话,就能省去繁复的账号密码输入过程。

3.7.1 确认是否本地存有密钥

首先,你需要确认自己是否已经拥有密钥。默认情况下,用户的SSH密钥存储在其~/.ssh目录下。进入该目录并列出其中内容,你便可以快速确认自己是否已拥有密钥:

$ cd ~/.ssh
$ ls

3.7.2 生成SSH key

打开gitbash,输入如下代码:

$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
  • 用自己的github账号邮箱替换上面的邮箱

  • 如果提示文件夹,默认即可,直接按Enter

  • 如果提示密码,不设密码的话,也直接按Enter

确保已经运行密钥:

$ eval $(ssh-agent -s)

把密钥添加到本地代理:

$ ssh-add ~/.ssh/id_rsa

3.7.3 查看并拷贝密钥

默认生成路径下,可以输入如下代码查看密钥:

$ cat ~/.ssh/id_rsa.pub

拷贝到剪贴板:

$ clip < ~/.ssh/id_rsa.pub
# Copies the contents of the id_rsa.pub file to your clipboard

3.7.4 把密钥添加到github账号

  • 账号登陆github

  • 点击头像,下拉点击setting

  • 点击SSH and GPG keys

  • 点击New SSH key 或者 Add SSH key

  • 粘贴密钥

  • title命名备注

  • 点击 Add SSH key

3.8 Github一机多账号SSH配置

需求情形:一台电脑上,可能需要使用不同的github账号(fangning 以及kevin),分别开展仓库开发和维护工作。

解决办法如下:

(1)分别在本地电脑上给两个github账号配置SSH。具体步骤参看:(节3.7: github帐号添加SSH key)。需要注意的是:

  • 务必重命名两个私钥,避免覆盖。例如:~/.ssh/fangning_id_rsa~/.ssh/kevin_id_rsa

  • 私钥位置(Windows系统):C:\Users\win-account\.ssh\

(2)全局配置两个账号的别名关系:

  • 首先,在私钥文件夹下创建(若无)并编辑配置文件:C:\Users\win-account\.ssh\config。(先用txt创建,然后删除扩展.txt

  • 其次,根据上述私钥文件位置编辑配置要求,然后保存:

# Default github account: fangning
Host fangning
   HostName github.com
   IdentityFile ~/.ssh/fangning_id_rsa
   IdentitiesOnly yes
   
# Other github account: kevin
Host kevin
   HostName github.com
   IdentityFile ~/.ssh/kevin_id_rsa
   IdentitiesOnly yes

(3)打开gitbash(默认路径下),确保私钥添加到系统代理中:

# 运行私钥代理
$ eval $(ssh-agent -s)
# 添加私钥1
$ ssh-add ~/.ssh/fangning_id_rsa
# 添加私钥2
$ ssh-add ~/.ssh/kevin_id_rsa

(4)测试私钥能与github服务器通讯:

$ ssh -T git@fangning
$ ssh -T git@kevin

如果通讯成功则可以看到:Hi kevin! You've successfully authenticated, but GitHub does not provide shell access.

(5)设定仓库的git配置文件(注意文件路径:path-of-your-repo/.git/config):

[remote "origin"]
    url = git@fangning:huhuaping/wp-xian.git
    fetch = +refs/heads/*:refs/remotes/origin/*

[user]
    name = fangning@github.email
    email = fangning' github email

此处的重点有三个:一是remote url的别名git@fangning,意味着git将会使用这一别名指定下的SSH私钥;二是github仓库地址huhuaping/wp-xian.git,此处因为fangning是仓库的合作者collaborator,拥有完全权限;三是仓库git用户[user],这里设置为fangning,也即意味着其为当前git使用者身份。第三点我们也可以使用git config user.email "fangning@github.email",以及git config user.name "fangning' github name"进行调整。

参考资源:

3.9 Github如何设置personal access token (PAT)

github更新安全机制,提出了PAT访问方式,以下是基本设置过程:

  • 使用usethis

  • 打开一个Rstudio项目(已经git托管)

  • Github创建PAT token:先在Rstudio 项目 Console中运行usethis::create_github_token(),浏览器将会自动登陆你的github网站,并引导进入PAT token设置。

  • PAT token申请:有效期可以自行设定,可以按年度来。设置好后,记得copy token码(后续将无法再看到它),下面将要用到。

  • 本地PAT设置:在Rstudio 项目 Console中运行gitcreds::gitcreds_set(),将会引导设置,要求输入PAT token,粘贴之前复制好的token即可。选择”2: Replace these credentials”。完成本地设置。

  • 重启Rstudio 项目,检查是否设置成功。

require(usethis)

# open github website and create your PAT
## copy the token
usethis::create_github_token()

# set local git configuration
## select 2: Replace these credentials
gitcreds::gitcreds_set()

# check that your PAT has been successfully stored 
usethis::gh_token_help()

参看资源:Managing Git(Hub) Credentials see

3.10 gitee与github联通

GitHub是全球最大的面向开源及私有软件项目的托管平台,里面不缺乏大神写的优秀的开源项目,可是GitHub有一个致命的弊端,就是国内访问速度太慢了。为了解决这个问题,一个优秀的国产代码托管平台Gitee(码云)应用而生。

下面将重点介绍如何实现一个项目仓库在gitee与github之间无缝联通和同步(相关过程可参看)。

3.10.1 gitee准备

  • 注册gitee账号(操作略)

  • 绑定邮箱

3.10.2 gitee添加SSH key

与前面github的添加过程(见节@ref(#github-sshkey))类似。也可以参看官方说明

  • 打开并运行gitbash

  • 查看确认本地密钥情况

# 进入个人user,列出密钥
$ cd ~/.ssh
$ ls
  • 生成gitee密钥(按提示完成三次Enter回车)。
# 生成SSH Key,邮箱仅作为识别符
$ ssh-keygen -t ed25519 -C "your_email@example.com" 
  • 运行密钥并添加到本地:
# 确保已经运行密钥
eval $(ssh-agent -s)

# 把密钥添加到本地代理
$ ssh-add ~/.ssh/id_ed25519
  • 查看密钥并拷贝密钥:
# 查看密钥
$ cat ~/.ssh/id_ed25519.pub

# 拷贝到剪贴板
$ clip < ~/.ssh/id_ed25519.pub
  • 登陆gitee网站,在个人账号下添加上述复制的SSH key:安全设置 \(\Rightarrow\) SSH公钥

  • gitbash添加主机到本机SSH可信列表

$ ssh -T git@gitee.com

3.10.3 将github仓库与gitee关联

考虑到主要使用github,gitee只是作为备用,因此下面介绍如何将github仓库关联到gitee。

主要步骤如下(相关过程可参看):

  • 确保github和gitee的SSH key都正确配置(参看节@ref(#github-sshkey)和节@ref(#gitee-sshkey))

  • 登陆gitee网站,通过引用github仓库进行gitee仓库创建:新建仓库 \(\Rightarrow\) 点击导入 \(\Rightarrow\) 导入GitHub仓库(需要github授权同意)\(\Rightarrow\) 选择目标仓库,点击导入

  • 使用gitbash克隆github目标仓库到本地

$ cd your-dir-path/
$ git clone git@github.com:user/your-rep.git
  • 修改目标仓库的git配置文件.git/config
[remote "origin"]
  # github 地址
    url = git@github.com:user-github/your-repo.git
    # gitee 地址
    url = git@gitee.com:user-gitee/your-repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
  • 此时,已经完成了github与gitee的同步关联。对本地克隆仓库的相关git操作,都会实现二者的同步变动。

3.11 git多设备协同

3.11.1 明确自己git使用的安全环境

github有多重安全条件,用户可以自行决定自己的安全等级。需要注意的是,在多台工作设备下,git需要确认不同设备的使用权限。因此,明确自己的安全环境是多设备工作的第一步:

  • 是否开启两步验证。若开启,在一些重要的安全操作下(登陆账户或删除仓库),就需要获得实时动态密码(token)。动态密码的管理工具包括authy等。

  • 是否设定加密SSH。简单说,如果本地电脑采用SSH key来与服务器对话,就能省去繁复的账号密码输入过程。

3.11.2 多设备git工作的基本流程

  • 条件准备。主力设备A;新设备B;需要异端工作的sharerepo。

  • 主力设备A:对sharerepo已完成工作进行push,上传到云端。add-commit-push三部曲。

  • 新设备B:创建文件夹,并clone云端的sharerepo。

# 明确存放在本地的文件路径
$ cd /j/github/

# clone远程sharerepo到本地文件路径下
$ git clone https://github.com/huhuaping/sharerepo.git

# 进入本地sharerepo
$ cd ./sharerepo
  • 工作设备下:pull-edit-add-commit-push 四部曲。

3.11.3 两步验证下如何正确地clone远程repo

  • 对于私有仓库,上述方法clone会提示错误。
Repository not found. fatal: repository not found
  • github托管下,两步验证法要求对新设备B设定私有进入授权码。github账号 ——>setting ——>Developer settings ——> personal access tokens ——> generate new token ——>勾选权限范围 ——> 复制授权码备用。

  • gitbash中输入如下代码colone私有仓库

# tokens 也就是上述复制备用的授权码。既不是github账户登录密码,也不是两步验证动态码!
$ git clone https://username:tokens@github.com/username/repo.git

3.11.4 最后的忠告

  • 在任何终端设备上工作,最后都要记得对修改进行add-commit-push三部曲操作

  • 云端永远保持最新状态!

参考资料1

参考资料2

3.12 git仓库协作

3.12.1 github的两种协作模式

(1)叉取和拉取模式(fork and pull model)

任何人都可以分叉现有的仓库,并将更改推送到他们的个人分支。您不需要对源仓库的权限来推送到用户拥有的分支。这个模式在开源项目中很受欢迎,因为它减少了新贡献者之间的摩擦,并允许人们在没有预先协调的情况下独立工作

(2)仓库共建共享模式(shared repository model)

协作者被授予对单个共享仓库的推送访问权限,并且在需要进行更改时创建主题分支。这种模式在小型团队和组织在私人项目上协作时更为普遍。

参看:GitHub for collaboration and best practices (page link)

3.12.2 github多人共创协作

(1)基本准备

  • 仓库所有人A创建完成github仓库

  • 协作伙伴B准备好自己的github账号(包括SSH设置)

(2)仓库所有者A邀请协作者B

  • A进入github 仓库,进入setting,点击collaborator,添加协作者add collaborator(输入github账号名或邮箱)

  • B查阅自己的github注册邮箱,在收到的邀请信中点击同意接受邀请。

(3)协作者B在自己电脑端使用终端命令(gitbash),拷贝A创建的源仓库。此时A和B同时具有对仓库的编辑和推送等操作权限。

(3)共创协作过程中,可能会出现“合并冲突”问题,这需要A和B共同商定处理和解决。推荐使用Rstudio提供的相关冲突解决处理界面。

参考资源:

3.12.3 git用户信息配置

(0)查看当前的配置情况:

# list settings
git config --list

(1)对单个仓库单独配置用户信息(Change Username and Email for Single Repository):

  • 首先进入仓库的工作母目录下,然后运行如下git命令:
git config user.name "Your Name"
git config user.email "your-email-address@domain.com"
  • 上述git配置将会覆盖全局git配置

(2)git用户信息全局配置(Setup Username & Email Globally)

git config --global user.name "Your Name"
git config --global user.email "your-email-address@domain.com"

参考资料:

  • How to know the git username and email saved during configuration? 参看

  • How to View or Change Git Username and Email Address 参看

  • Setting your username in Git 参看

3.13 git 自动化

3.13.1 git hooks (readme)

在编写R包时,通常会编写一个 README.Rmd 文件,然后将其呈现给 README.md。

问题是我会经常忘记渲染README.Rmd文件(rmarkdown::render('README.Rmd')),这意味着尽管保持最新,但其他readme.html页面仍旧会落后于更新。

要做到这一点很简单(参看),只需在”.git/hooks”文件夹中创建一个名为”pre-commit”的文件,内容如下:

#!/bin/sh

if [ README.Rmd -nt README.md ]
then
        R -e "rmarkdown::render('README.Rmd')"
        git add README.md
fi

然后你只需要在Terminal窗口中$ git add .,就可以自动渲染README.Rmd文件。

注意 git add .后会生成”readme.html”文件,因此还需要再add一遍,然后再commit,最后push

3.13.2 github action

在网页数据抓取中,github action可以实现云端无人值守的自动化数据抓取。

github action 通过.github/workflows/your-action-setting.yaml文件(可参看我的yaml file)来定义自动化工作流。

下面记录几个经验法则:

(1)github 仓库类型会影响github action的调用权限和使用次数。因此,github 仓库最好是以公开方式(public),而不是私有方式(private)。因为github action对公开型仓库可以无限制使用(参看我的covid19仓库),而对私有仓库则采取定价收费方式。

(2)虚拟机操作系统的选择也很关键。经过测试,使用macos-latest是一个比较可靠的选择。

jobs:
  # This workflow contains a single job called "generate-data"
  generate-data:
    # The type of runner that the job will run on
    runs-on: macos-latest

(3)时间规划要考虑时区问题。cron规则使用的是UTC时间(各种原因可参看博文),而UTC time = Shanghai time - 8 hours

name: Scrape covid19 risk area
on:
  schedule:
    - cron: '30 1,4,7,11,14 * * *'   
    # UTC time = sahnghai time - 8 hours
    - cron: '30 9,12,15,19,22 * * *'  
    # shanghai time = UTC time + 8 hours

(3)renv的包环境管理可以大大节约环境准备时间。具体而言:第1步进行本地操作。本地电脑上先运行renv,并把所有需要的R包进行安装,renv::snapshot()保存好所有包记录,然后提交。第2步配置github action .yml文件。其中的一个关键在于renv的路径配置,不同的操作系统renv路径各不相同(见下表,具体参看renv官网说明)。另一个关键在于,正确指定云端runner调用缓存的R环境,包括R包。

 - uses: actions/cache@v2
        with:
          path: ~/Library/Application Support/renv #~/.local/share/renv
          key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }}
          restore-keys: |
            ${{ runner.os }}-renv-
      - name: Install dependencies
        run: |
          renv::restore()
        shell: Rscript {0}
Platform Location
Linux ~/.local/share/renv
macOS ~/Library/Application Support/renv
Windows %LOCALAPPDATA%/renv

(4)RSelenium进行动态网站抓取。在scrape.R文件中,可以如常使用RSelenium包进行动态网站内容抓取,但是最好调用Firefox浏览器(chrome浏览器更新会带来了一些bug,例如对网站的访问限制等) 。

- uses: browser-actions/setup-firefox@latest 
      - run: firefox --version
      
      - name: Scrape the data
        run: |
          source("scrape-covid19.R", encoding='UTF-8')
        shell: Rscript {0}

相关学习资源: