曾经沧海难为水,除却巫山不是|

Joey-Wang

园龄:4年3个月粉丝:17关注:0

📂Git
🔖Git
2021-03-16 02:27阅读: 255评论: 0推荐: 0

Git 与 GitHub 使用指南

Git是实现分布式版本控制的一个工具,简单的来说就是实现文件历史管理的工具。是位于本地的仓库。

GitHub是世界上最大的软件远程仓库,是一个面向开源和私有软件项目的托管平台,使用Git做分布式版本控制。

第一章 Git

1.1 安装 Git

macOS已经安装了 Git,可尝试命令 git --version 查看Git版本。若未显示Git版本,会提示你安装或升级 Git,按提示操作即可。
也可访问Git网站主页,有下载链接。

1.2 配置 Git

Git 需要你的用户名及邮箱,以跟踪谁修改了项目。通过以下命令配置用户名及密码:

git config --global user.name "username"
git config --global user.email "username@example.com"

若未配置,在首次提交时 Git 会提示你提供这些信息。若要查看当前用户名及邮箱信息:

cat ~/.gitconfig

1.3 Git 使用(即管理本地仓库)

1.3.1 创建项目

创建一个要进行版本控制的项目。首先创建一个文件夹 folder,在此文件夹中创建文件 file。

1.3.2 忽略文件

若 folder 中存在无需 Git 跟踪的文件,需在此 folder 中创建一个名为 .gitignore 的特殊文件,在此文件中添加需忽略的文件/文件夹的相对目录。

🌰 我们的项目是个Python程序,扩展名为 .pyc 的文件是根据 .py 文件自动生成的,故无需让 Git 跟踪它们。这些文件存储在当前目录下的 __pycache__ 目录中,目录结构如下:

folder
|—— pythonFile.py
—— __pycache__
—— .gitignore

故 .gitignore 文件中添加内容:

__pycache__/

则能让 Git 忽略目录 __pycache__ 中的所有文件。

1.3.3 初始化仓库

终端切换到 folder 目录下,执行命令:

git init

则 Git 会在 folder 目录下初始化一个空仓库。仓库 ——程序中被 Git 主动跟踪的一组文件,.gitignore文件中的文件会被忽略。

此操作实质是在该目录下创建了 .git 目录。Git 用于管理仓库的文件都存储在 .git 目录中。删除此目录会丢失项目的所有历史记录。

1.3.4 检查状态

要检查项目的状态,需执行命令:

git status

提示:

image-20210313154405908

在 Git 中,分支 是项目的一个版本,提交 是项目在特定时点的快照。master是默认分支。

提示中指出了未被跟踪的文件(Untracked files)有哪些,并说我们尚未将任何东西添加到当前提交中,但指出了可能需要加入仓库的未跟踪文件。

1.3.5 将文件加入仓库

要将某些文件加入仓库,需执行命令:

git add file1 file2

若要将项目中未被跟踪的所有文件都加入仓库,可执行命令:

git add .

1.3.6 执行提交

执行命令:

git commit -m "message"

标志-m让 Git 将接下来的消息 message 记录到项目的历史记录中。

输出:

image-20210313174839187

3 file changed:3个文件被改动(我们新添加了3个文件);31 insertions:插入了32行内容。

此时检查状态,提示我们位于 master 分支,且工作树是干净的。这是我们每次提交项目的可行状态时都希望看到的消息。否则需仔细阅读,可能提交前忘记添加某些文件。

image-20210313174936760

1.3.7 查看提交历史

执行命令:

git log

输出:

image-20210313175314677

每次提交时,Git 都会生成唯一的引用ID,长40字符。它记录了提交者的用户信息、提交时间、提交时指定的消息。

提交的引用ID是提交的 唯一凭据

可通过标志 --pretty=online 打印提交历史条目的简单版本:提交的引用ID 、提交记录的消息。

git log --pretty=online

1.3.8 第二次提交

我们在首次提交后,对文件进行了修改后想进行二次提交,可执行命令:

git commit -am "message"

标志 -a 让 Git 将仓库中所有修改了的文件都加入当前提交中。标志-m让 Git 在提交历史中记录一条消息。

如果在两次提交之间创建了新文件,可再次执行命令 git add . 将这些新文件加入到仓库中。

1.3.9 撤销修改

我们修改文件后,若想撤销此次所有文件修改,恢复到最后一个提交的版本,可执行命令:

git checkout .

即可放弃最后一次提交后作出的所有修改,将项恢复到最后一次提交的状态。

git checkout 文件名

此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。已添加到暂存区的改动以及新文件都不会受到影响。

1.3.10 提交回退

若要回退到之前的某个提交,执行命令:

git reset --hard 提交的引用ID前6字符

也可不用引用ID,Git中使用 HEAD 表示当前提交, HEAD^ 表示上一个提交, HEAD^^ 表示上上个提交, HEAD~100 表示前100个提交。

Git的提交回退速度非常快,因为Git在内部有个指向当前提交的HEAD指针,当你回退提交的时候,Git仅仅是把HEAD从指向某个提交:

image-20210313163203648

若回退到了旧提交,后悔了又想恢复到新提交,则需要找到新提交的引用ID。Git提供了一个命令 git reflog 用来记录你的每一次命令。

1.3.11 关于分支

创建并切换到某分支(原理就是将HEAD指针指向另一个分支,同时将其覆盖):

git checkout -b 分支名

切换回主分支:

git checkout master

删除某分支:

git branch -d 分支名

除非你将分支推送到远端仓库,不然该分支就是 不为他人所见的(关于远端仓库详见第二章):

git push origin 分支名

关于checkout 与 reset 的区别

1.3.12 删除仓库

若仓库的历史记录被弄乱了不知如何恢复,可直接将项目的历史记录删除——删除目录 .git。重新创建一个仓库,重新对修改进行跟踪。

rm -rf .git
git init
git status
git add .
git commit -m "Starting over."

1.3.13 删除未提交的文件

从工作区中删除未跟踪的文件,即新建的没有提交过的文件。

git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] <path>…

-d:可以删除文件夹,因为默认是删除的是file。

-f:代表强制,如果clean.requireForce配置的为true,则git clean会执行失败,此时可以使用git clean -f强制执行。

-i:interactive,可交互的删除文件或目录。

-n:dry-run,加入了这个参数,会提示你将会删除哪些文件,但不会删除这些文件。如果确定是你要删除的文件,将-n这个参数去掉后再执行。

第二章 GitHub

2.1 使用 GitHub

  1. 注册GitHub官网账号

  2. 创建 SSH Key

    • 在用户主目录下,查看有无 .ssh 目录,若有,再查看这个目录下有无文件 id_rsa 和 id_rsa.pub,若有,可直接跳到下一步。若没有,打开Shell,创建SSH Key:

      ssh-keygen -t rsa -C "youremail@example.com"
      

      需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。

    • 如果一切顺利的话,可在用户主目录里找到 .ssh 目录,里面有 id_rsaid_rsa.pub 两个文件,这两个就是 SSH Key 的秘钥对,id_rsa 是私钥,不能泄露出去,id_rsa.pub 是公钥,可以放心地告诉任何人。

    • 打开id_rsa.pub,复制里面的内容。

  3. 登陆GitHub,打开 “settings”,“SSH Keys and GPG keys” 页面:

    • 点“New SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容即可。

      image-20210313164614820
    • 点“Add Key”,你就应该看到已经添加的Key。

      image-20210313174048168
  4. 测试SSH连接:

    ssh -T git@github.com
    

为什么GitHub需要SSH Key呢?
因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

GitHub允许你添加多个Key。只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

友情提示:在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以不要把敏感信息放进去。

ssh是一种加密传输协议,如果git项目(以github上的项目为例子)地址是HTTPS开头则不需要配置ssh,如果是以GIT开头则必须配置ssh.

2.2 创建远程仓库

登陆GitHub,然后,在右上角找到“New repository”按钮,创建一个新的仓库。

image-20210313174310325

来到这个项目的主页,可以看到主页提供了两种和本地仓库关联起来的方式。

image-20210313174409214

方法一:把本地已有的同名 Git 仓库和 GitHub 上的仓库关联起来。

  1. 我们在 Git 使用中学会了如何创建并提交本地仓库(假设在本地新建文件夹 alien_invasion,如有需要可以添加.gitignore文件以及readme):

    git init
    git add .
    git commit -m "first commit"
    
  2. 到此,我们需将本地仓库和远程仓库相关联:

    1. SSH连接:

      git remote add origin git@github.com:Angelia-Wang/alien_invasion.git
      
    2. HTTPS连接:

      git remote add origin https://github.com/Angelia-Wang/alien_invasion.git
      

    远程库的名字就是 origin ,这是 Git 默认的叫法,也可以改成别的,但是 origin 这个名字一看就知道是远程库。

    远程库地址中的账户名一定是自己的,否则你在本地关联的就是别人的远程库,关联没有问题,但是以后无法将代码推送上去,因为你的SSH Key公钥不在别人的账户列表中。

    查看所有的远程仓库:

    git remote -v
    

    查看某远程仓库的详细信息:

    git remote show 远程库名
    

    删除某远程仓库:

    git remote rm 远程库名称
    

    更新远程仓库 url:(远程库名称推荐使用默认名称origin)

    git remote set-url origin <newurl>
    
  3. 把本地库的所有内容推送到远程库上

    git push -u origin master
    

    由于远程库是空的,我们第一次推送master分支时,加上了 -u 参数,Git不但会把本地的 master 分支内容推送的远程新的 master 分支,还会把本地的 master 分支和远程的 master 分支相关联,在以后的推送或者拉取时就可以简化命令。

    图中推送到了main分支,因为本地创建了main分支,我这里没有这样做,还是用master分支

  4. 之后的使用:

    本地仓库git add git commit-m之后,你的改动现已在本地仓库的 HEAD 中。执行如下命令以将这些改动提交到远端仓库:

    git push origin master
    

    可以把 master 换成你想要推送的任何分支。

方法二:直接从远程仓库克隆。

方法一适用于先有本地仓库,后有远程库时,如何关联远程库。若我们从零开始开发,那么最好的方式是先创建远程库,然后,从远程库克隆。

首先,登陆 GitHub,创建一个新的仓库,名字叫 Gittest。仓库有 SSH 地址。我们本地使用如下命令将仓库克隆下来:

git clone git@github.com:账户名/Gittest.git

也可克隆其他公共的仓库。

接下来就可在编辑本地内容后,推送到远程库上:

git push -u origin master

2.3 更新与合并

要更新你的本地仓库至最新改动,执行:

git pull

以在你的工作目录中 获取(fetch)合并(merge) 远端的改动。

要合并其他分支到你的当前分支(例如 master),执行:

git merge 分支名

git 会尝试去自动合并改动,但这可能并非每次都成功,可能出现 冲突(conflicts)。 这时候就需要你修改这些文件来手动合并这些冲突,改完之后,你需要执行如下命令以将它们标记为合并成功:

git add 文件名

在合并改动之前,你可以使用如下命令预览差异:

git diff 源分支 目标分支

2.4 替换本地改动

若只是更改本地的更改,恢复到上一次提交,可使用 checkout 命令。(具体见1.3.9)

假如你想丢弃你在本地的所有改动与提交,可以到服务器上获取最新的版本历史,并将你本地主分支指向它:

git fetch origin
git reset --hard origin/master

2.5 添加第三方库

git submodule 把第三方的版本库合并到自己的库中.

git submodule add 仓库地址 [目录路径](若直接添加到当前目录,则不需要此项)
git submodule add https://github.com/libevent/libevent deps/libevent

2.6 rebase 变基

两个分支master和feature,其中feature是在提交点B处从master上拉出的分支

master上有一个新提交M,feature上有两个新提交C和D

image-20221019222642953

此时切换到feature分支上,执行如下命令,相当于是想要把master分支合并到feature分支(这一步的场景就可以类比为我们在自己的分支feature上开发了一段时间了,准备从主干master上拉一下最新改动)

git checkout feature
git rebase master
// 这两条命令等价于 git rebase master feature

下图为变基后的提交节点图,解释一下其工作原理:

image-20221019222711349
  • feature:待变基分支、当前分支
  • master:基分支、目标分支

官方解释:当执行rebase操作时,git会从两个分支的共同祖先开始提取待变基分支上的修改,然后将待变基分支指向基分支的最新提交,最后将刚才提取的修改应用到基分支的最新提交的后面。

结合例子解释:当在feature分支上执行git rebase master时,git会从master和featuer的共同祖先B开始提取feature分支上的修改,也就是C和D两个提交,先提取到。然后将feature分支指向master分支的最新提交上,也就是M。最后把提取的C和D接到M后面,但这个过程是删除原来的C和D,生成新的C’和D’,他们的提交内容一样,但commit id不同。feature自然最后也是指向D’。

通俗解释❗️:rebase,变基,可以直接理解为改变基底。feature分支是基于master分支的B拉出来的分支,feature的基底是B。而master在B之后有新的提交,就相当于此时要用master上新的提交来作为feature分支的新基底。实际操作为把B之后feature的提交存下来,然后删掉原来这些提交,再找到master的最新提交位置,把存下来的提交再接上去(新节点新commit id),如此feature分支的基底就相当于变成了M而不是原来的B了。(注意,如果master上在B以后没有新提交,那么就还是用原来的B作为基,rebase操作相当于无效,此时和git merge就基本没区别了,差异只在于git merge会多一条记录Merge操作的提交记录)

上面的例子可抽象为如下实际工作场景:
张三从B拉了代码进行开发,目前提交了两次,开发到D了;李四也从B拉出来开发了并且开发完毕,他提交到了M,然后合到主干上了。此时张三想拉下最新代码,于是他在feature分支上执行了git rebase master,即把master分支给rebase过来,由于李四更早开发完并合了主干,如此就相当于张三是基于李四的最新提交M进行的开发了。

2.7 fork公共仓库并改为私有的

方法二为bustub官方推荐。目前不清楚这两种方法是否有区别,但实际尝试中两种方法中,第一种方法会跳出不明的 pull request,第二种不会。

方法一

  1. 在 “create a new repository” 页面选择“import a repository”。
image-20221114165800594
  1. 填上要clone仓库的url和想创建的私有仓库的名称,然后选择“Private”,最后点击“Begin Import”。
image-20221114165617496
  1. 将该private仓库clone到本地开发后,添加原public仓库作为第二个remote,这便于及时获取公共库后续的更改。
# 查看所有的远程库
$ git remote -v   
# 添加远程库,取名为public
$ git remote add public https://github.com/cmu-db/bustub.git 

方法二

  1. 在“create a new repository” 页面中直接创建一个private仓库,如 bustub-private。

  2. 在本地创建一个原仓库的 bare clone,取名 bustub-public:

$ git clone --bare https://github.com/cmu-db/bustub.git bustub-public
  1. 将原public仓库 mirror 到我们自己的private方库,这样就将public仓库的所有东西都推到private仓库中:
$ cd bustub-public

# If you pull / push over HTTPS
$ git push https://github.com/student/bustub-private.git master
# If you pull / push over SSH
$ git push git@github.com:student/bustub-private.git master
  1. 删除本地对public仓库的clone:
$ cd ..
$ rm -rf bustub-public
  1. 将自己private仓库clone到本地机器:
# If you pull / push over HTTPS
$ git clone https://github.com/student/bustub-private.git
# If you pull / push over SSH
$ git clone git@github.com:student/bustub-private.git
  1. 添加public库作为第二个remote,这便于及时获取公共库后续的更改。
$ git remote add public https://github.com/cmu-db/bustub.git
  1. 我们可以查看现有的远程库信息,来确认已经添加好了remote
$ git remote -v
origin	https://github.com/student/bustub-private.git (fetch)
origin	https://github.com/student/bustub-private.git (push)
public	https://github.com/cmu-db/bustub.git (fetch)
public	https://github.com/cmu-db/bustub.git (push)

2.8 获取fork的仓库的最新更新

# 添加公共库的remote:
$ git remote add \
    public https://github.com/cmu-db/bustub.git
# 后续拉取公共库的最新更改:
$ git fetch public
$ git merge public/master

2.* 错误汇总

  1. 远程仓库有东西的情况下,将本地别的仓库同步上去会报错:

    refusing to merge unrelated histories(拒绝合并不相关的历史)

    出现这个问题的最主要原因还是在于本地仓库和远程仓库实际上是独立的两个仓库。假如我之前是直接clone的方式在本地建立起远程github仓库的克隆本地仓库就不会有这问题了。

    解决方法:

    在pull命令后紧接着使用--allow-unrelated-histories选项来解决问题(该选项可以合并两个独立启动仓库的历史)。

    git pull origin master --allow-unrelated-histories
    
  2. 在使用 git 拉取github代码库的时候出现以下错误

    LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443

    解决方法如下:

    # 1. 取消全局代理
    git config --global --unset https.proxy
    git config --global --unset http.proxy
    # 2. 配置全局代理。注意1080改为自己代理服务的端口号
    git config --global http.https://github.com.proxy socks5://127.0.0.1:1080 
    git config --global https.https://github.com.proxy socks5://127.0.0.1:1080
    
    
  3. 在使用 git submodule update --init --recursive 时遇到错误

    Fetched in submodule path 'contrib/minizip-ng', but it did not contain 6cffc951851620e0fac1993be75e4713c334de03. Direct fetching of that commit failed.

    git submodule deinit -f .
    git submodule update --init --recursive
    

参考

https://www.jianshu.com/p/296d22275cdd

本文作者:Joey-Wang

本文链接:https://www.cnblogs.com/joey-wang/p/14541153.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Joey-Wang  阅读(255)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开