git 中容易遗忘的点!

推送/抓取 指定分支

推送分支

推送分支,就是把该分支上的所有本地提交推送到远程库。推送时要指定本地分支,这样Git就会把该分支推送到远程库对应的远程分支上:

java 复制代码
$ git push origin master

如果要推送其他分支,比如dev,就改成:

java 复制代码
$ git push origin dev

如果 git pull 提示:

There is no tracking information for the current branch.Please specify which branch you want to merge with.

说明本地分支和远程分支的连接关系没有创建 ,用命令git branch --set-upstream-to=origin/<branch-name> <branch-name>创建关联(本地和远程分支的名称最好一致)

抓取分支

多人协作时,大家都会往master和dev分支上推送各自的修改。

现在,模拟一个你的小伙伴A,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者 同一台电脑的另一个目录下克隆:

java 复制代码
$ git clone git@github.com:pbw-langwang/gitskills.git
Cloning into 'gitskills'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.

当A从远程库clone时,默认情况下,A只能看到本地的master分支。不信可以用 git branch 命令看看:

java 复制代码
$ git branch
* master

现在,A要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支(前提是你的远程厂库有dev分支,不然这样是不行的):

java 复制代码
$ git switch -c dev origin/dev

如果远程仓库没有dev分支,会报错:

java 复制代码
invalid reference: origin/dev

解决办法是:先自己创建该分支,然后push,再回到这里使用就好了!

理解工作区和暂存区

Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念

工作区(Working Directory):

工作区 就是你在电脑里能看到的目录就是一个工作区:

版本库(Repository)

工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库

Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。

前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:

  • 第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区
  • 第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支

你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。(这里就是为什么可以add多个文件后,一次性commit)

还是实践出真理,大家可以修改一下自己的文件,然后再新建一个文本文件到工作区(暂时不用提交到git仓库),然后运行 git status 看看,菜鸟的结果如下:

java 复制代码
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   readme.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        LICENSE

no changes added to commit (use "git add" and/or "git commit -a")

Git非常清楚地告诉我们,readme.txt 被修改了(Changes not staged),而 LICENSE 还从来没有被添加过,所以它的状态是 Untracked

现在,使用两次命令 git add ,把 readme.txt 和 LICENSE 都添加后,用 git status 再查看一下:

java 复制代码
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   readme.txt
        new file:   LICENSE

如果报错

warning: LF will be replaced by CRLF in test1.txt. The file will have its original

可以不管,但是菜鸟不能让问题溜走,解决办法

现在,暂存区的状态就变成这样了:

所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage) ,然后,执行git commit就可以一次性把暂存区的所有修改提交到分支

一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是 "干净" 的:

理解分支与分叉

见:git 自我研究:分支与分叉

为什么Git比其他版本控制系统设计得优秀?

为什么Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件

为什么说Git管理的是修改,而不是文件呢?

我们还是做实验。第一步,对 readme.txt 做一个修改,比如:加一行内容,然后添加到暂存区,然后再次修改readme.txt ,最后提交到git仓库。提交后,再用git status看看状态:

java 复制代码
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   readme.txt

no changes added to commit (use "git add" and/or "git commit -a")

怎么第二次的修改没有被提交?

别激动,我们回顾一下操作过程:

第一次修改 -> git add -> 第二次修改 -> git commit

我们前面讲了,Git管理的是修改,当你用git add命令后 ,在工作区的第一次修改被放入暂存区,准备提交,但是,在工作区的第二次修改并没有放入暂存区,所以 git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。

提交后,用git diff命令可以查看工作区和版本库里面最新版本的区别:

java 复制代码
warning: LF will be replaced by CRLF in gittwo.
The file will have its original line endings in your working directory
diff --git a/readme.txt b/readme.txt
index da64460..ab83e4f 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,3 +1,3 @@
 this is two git!
 try change to see status!
-try xiugai!
+try guanlixiugai!

可见,第二次修改确实没有被提交。(读者修改肯定跟我不一样,所以以自己为准)

那怎么提交第二次修改呢?你可以继续git add再git commit,也可以别着急提交第一次修改,先git add第二次修改,再git commit,就相当于把两次修改合并后一块提交了:

第一次修改 -> git add -> 第二次修改 -> git add -> git commit

git branch 和 git switch

r 复制代码
git checkout -b dev

git switch -c dev

git branch dev
git checkout dev

git branch dev
git switch dev

注:

git checkout 这个命令承担了太多职责,既被用来切换分支,又被用来恢复工作区文件,对用户造成了很大的认知负担。

Git社区发布了Git的新版本2.23。在该版本中,有一个特性非常引人瞩目,就是新版本的Git引入了两个新命令 git switch 和 git restore,用以替代现在的 git checkout。

git remote

要查看远程库的信息,用 git remote

java 复制代码
$ git remote
origin

git remote -v显示更详细的信息:

  1. https
java 复制代码
$ git remote -v
origin  https://github.com/pbw-langwang/gitskills.git (fetch)
origin  https://github.com/pbw-langwang/gitskills.git (push)
  1. ssh
java 复制代码
$ git remote -v
origin  git@github.com:pbw-langwang/gitskills.git (fetch)
origin  git@github.com:pbw-langwang/gitskills.git (push)

上面显示了可以抓取(fetch)和推送(push)的origin的地址。如果没有推送权限,就看不到push的地址。

git log

git log 其实有很多参数,且不同参数能看见的东西不一样,这里菜鸟推荐一个命令(来自廖雪峰大佬):

git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

其效果:

vim 复制代码
$ git lg
*   =format:61fea98 - (HEAD -> master, origin/dev2) Merge branch 'dev2' of github.com:pbw-langwang/gitskills (22 hours ago) <*>
|\
| * =format:1cf6ec6 - add dev2 (23 hours ago) <*>
* | =format:5d06e73 - (origin/master, origin/HEAD) change b.txt (25 hours ago) <*>
* |   =format:8a5cb29 - fix master and dev (26 hours ago) <*>
|\ \
| * \   =format:b144529 - (origin/dev) fix env conflict (27 hours ago) <*>
| |\ \
| | * | =format:13c0bba - add env (27 hours ago) <*>
| * | | =format:6b07599 - b aaddenv (27 hours ago) <*>
| |/ /
| * / =format:e0e5529 - add dev (28 hours ago) <*>
| |/
| * =format:180d386 - add b (29 hours ago) <*>
|/
* =format:036b30f - Initial commit (9 days ago) <*>

想退出直接按q就行!

GitHub远程仓库

GitHub远程仓库,这里读者自己注册GitHub账号

GitHub添加ssh

第一步:创建SSH Key 。在用户主目录下(一般是:c://Users/asus/ 或者 自己全盘搜一下),看看有没有.ssh目录 ,如果有,再看看这个目录下有没有 id_rsaid_rsa.pub 这两个文件,如果已经有了,可直接跳到下一步。如果没有,在git仓库处打开Git Bash,创建SSH Key:

perl 复制代码
ssh-keygen -t rsa -C "youremail@example.com"

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

第二步:打开GitHub

添加title,随便什么都可以。

填写key,自己的.ssh里面的id_rsa.pub文件的内容。

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

GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

GitHub创建仓库

Repository name 按照自己的git仓库起名就好,其它默认(不要选创建readme文件),然后确定。

目前,在GitHub上的这个Git_warehouse仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后把本地仓库的内容推送到GitHub仓库。

关联仓库

现在,我们根据GitHub的提示,在本地的Git_warehouse仓库下运行命令:

java 复制代码
git remote add origin https://github.com/pbw-langwang/Git_warehouse.git(推荐)
git remote add origin git@github.com:pbw-langwang/Git_warehouse.git

注意:把上面的pbw-langwang替换成你自己的GitHub账户名,否则你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。

添加后,远程库的名字就是origin ,这是Git默认的叫法,也可以改成别的。

然后执行:

java 复制代码
git push -u origin master

出现输入GitHub用户名和密码界面 (https是这样,ssh菜鸟没试,如果有警告可以看看下面的SSH警告)

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

刷新GitHub页面,看到远程库的内容已经和本地一模一样:

从现在起,只要本地作了提交,就可以通过命令:

java 复制代码
git push origin master

把本地master分支的最新修改推送至GitHub,现在,你就拥有了真正的分布式版本库!

SSH警告

当你第一次使用Git的clone或者push命令连接GitHub时,会得到一个警告:

java 复制代码
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?

这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。(如果你是用的https,则不会警告这个)

Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了:

java 复制代码
Warning: Permanently added 'github.com' (RSA) to the list of known hosts

这个警告只会出现一次,后面的操作就不会有任何警告了。

如果你实在担心有人冒充GitHub服务器,输入yes前可以对照GitHub的RSA Key的指纹信息是否与SSH连接给出的一致。

小结

  1. 要关联一个远程库,使用命令 git remote add origin https://github.com/pbw-langwang/Git_warehouse.git
  2. 关联后,使用命令 git push -u origin master 第一次推送master分支的所有内容
  3. 此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改
  4. 一个工作区可以关联好几个远程仓库
  5. 分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步
相关推荐
琴~~13 分钟前
ant-design-vue中table某一列进行合并
前端·javascript·vue.js
sunly_1 小时前
Flutter:flutter_screenutil屏幕适配
前端·javascript·flutter
俸涛努力学前端1 小时前
ajax (一)
开发语言·前端·javascript·笔记·ajax
凌虚(失业了求个工作)2 小时前
Web 端语音对话 AI 示例:使用 Whisper 和 llama.cpp 构建语音聊天机器人
前端·人工智能·python·whisper·llama
信息化未来2 小时前
odoo17 档案管理之翻译2
java·服务器·前端
川石课堂软件测试2 小时前
UI自动化测试|web端元素获取&元素等待实践
开发语言·前端·功能测试·算法·ui
糯米w2 小时前
【前端】excel文件对比
前端·javascript·excel
Ace_31750887762 小时前
微店商品详情接口技术实现详解及代码示例
前端
南城巷陌2 小时前
node.js中实现router模块化管理
前端·javascript·node.js·express.router
new Vue()2 小时前
ES6中Promise的使用场景
开发语言·前端·javascript