Git基本使用(二)

远程仓库

本文以Gitee为例作为远程仓库

SSH设置

注册好gitee账号后,可以通过设置SSH来避免每次远程操作都输入账号密码。首先应该在本地生成sshkey,在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

ssh-keygen -t ed25519 -C "xxxxx@xxxxx.com" 

注意:这里的 xxxxx@xxxxx.com 只是生成的 sshkey 的名称,并不约束或要求具体命名为某个邮箱。
现网的大部分教程均讲解的使用邮箱生成,其一开始的初衷仅仅是为了便于辨识所以使用了邮箱。

在这里插入图片描述

复制生成后的 ssh key,通过仓库主页 「个人」->「安全设置」->「ssh公钥」 ,添加生成的 public key 添加到仓库中。

添加后,在终端(Terminal)中输入

ssh -T git@gitee.com

首次使用需要确认并添加主机到本机SSH可信列表。若返回 Hi XXX! You've successfully authenticated, but Gitee.com does not provide shell access. 内容,则证明添加成功。

gitee用户邮箱

在gitee中要配置提交的邮箱,这个邮箱用于提交时账号的认证,如果提交时的本地邮箱和gitee设置的邮箱一致,则这次提交统计到该账号的一次提交。

在这里插入图片描述

如果本地的邮箱和gitee的不一致,那么在提交时,会以另一个用户的身份来统计。

在这里插入图片描述

也可以设置只有指定的邮箱次可以推送

在这里插入图片描述

一个电脑连多个远程仓库

一个SSH

如果同时需要配置多个仓库的连接,比如同时配置github和gitee。其实可以使用同一份公钥,将这个公钥同时配到github和gitee中去,然后如果需要指定的username和email时,可以在相应的目录中可以设置username和email。比如在最初的配置时,使用了

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

这个假设用于gitee,为默认值。那么如果想要在github中推代码,可以在目录中重新设置username和email,这次设置时不夹global,只对当前的目录生效。

git config --global user.name "Your GithubName"
git config --global user.email "githubEmail@example.com"
多个SSH
  1. 生成一个github用的SSH-Key
$ ssh-keygen -t rsa -C 'xxxxx@company.com' -f ~/.ssh/gitee_id_rsa
  1. 生成一个gitee用的SSH-Key
$ ssh-keygen -t rsa -C 'xxxxx@qq.com' -f ~/.ssh/github_id_rsa
  1. 在 ~/.ssh 目录下新建一个config文件,添加如下内容(其中Host和HostName填写git服务器的域名,IdentityFile指定私钥的路径)
# gitee
Host gitee.com
HostName gitee.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/gitee_id_rsa
# github
Host github.com
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/github_id_rsa

4.用ssh命令分别测试

$ ssh -T git@gitee.com
$ ssh -T git@github.com

建立Gitee仓库

在gitee中可以建立自己的远程仓库

在这里插入图片描述

1、在新建仓库页面填写仓库信息。仓库相关概念说明如下:

  • 仓库名称: 仓库的名称,用于仓库命名
  • 归属:仓库归属账户,可以是个人账号/组织/企业中的一种,创建成功后该账户默认为仓库的拥有者(管理员)
  • 路径:仓库的git访问路径,由用户个性地址+仓库路径名称组成。创建仓库后用户将通过该路径访问仓库。
  • 仓库介绍:仓库的简单介绍
  • 是否开源:设置仓库是否为公开仓库,公开仓库对所有人可见,私有仓库仅限仓库成员可见。
  • 选择语言:仓库主要开发用的编程语言
  • 添加.gitignore:系统默认提供的git忽略提交的文件模板,设置.gitignore后将默认忽略指定目录/文件到仓库
  • 添加开源许可证:如果仓库为公开仓库,可以添加设置仓库的开源协议,作为对当前项目仓库和衍生项目仓库许可约束,开源许可证决定了该开源项目是否对商业友好。
  • Readme:项目仓库自述文档,通常包含有软件的描述或使用的注意事项。
  • 使用\**\*模板文件初始化仓库:使用IssuePull Request文件模板初始化仓库
    在这里插入图片描述

点击创建后就可以创建自己的远程gitee仓库。然后就可以将本地仓库的文件推至远程仓库。

方法一、先将仓库clone到本地,然后再push到gitee仓库

$ git clone https://gitee.com/用户个性地址/HelloGitee.git #将远程仓库克隆到本地

在克隆过程中,如果仓库是一个私有仓库,将会要求用户输入 Gitee 的账号和密码。按照提示输入即可。

当然,用户也可以通过配置本地的git配置信息,执行git config命令预先配置好相关的用户信息,配置执行如下:

$ git config --global user.name "你的名字或昵称"
$ git config --global user.email "你的邮箱"

在 Gitee 平台中,强烈建议您在【设置-多邮箱管理】中的“提交邮箱”与上面配置信息中的邮箱地址保持一致,这样平台就能及时地统计您在平台中提交代码的贡献了。

修改代码后,在仓库目录下执行下面命令

$ git add . #将当前目录所有文件添加到git暂存区
$ git commit -m "my first commit" #提交并备注提交信息
$ git push origin master #将本地提交推送到远程仓库

方法二、本地初始化一个仓库,设置远程仓库地址后,再push

在本地的learngit仓库下运行命令:

$ git remote add origin git@gitee.com:xxx/learngit.git

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

$ git push -u origin master

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

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

$ git push origin master

在新建仓库时,如果在 Gitee 平台仓库上已经存在 readme 或其他文件,在提交时可能会存在冲突,这时用户需要选择的是保留线上的文件或者舍弃线上的文件,如果您舍弃线上的文件,则在推送时选择强制推送,强制推送需要执行下面的命令(默认不推荐该行为):

$ git push origin master -f

如果您选择保留线上的 readme 文件,则需要先执行:

$ git pull origin master

SSH警告

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

The authenticity of host 'gitee.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连接在第一次验证Gitee服务器的Key时,需要你确认Gitee的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。

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

Warning: Permanently added 'gitee.com' (RSA) to the list of known hosts.

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

删除远程库

如果添加的地址写错了,或者想删除远程库,可以用git remote rm <name>命令,使用前,最好先使用git remote -v查看远程库信息:

$ git remote -v
origin  git@gitee.com:gitnpr/notes-and-knowledge.git (fetch)
origin  git@gitee.com:gitnpr/notes-and-knowledge.git (push)

然后,根据名字删除,比如删除origin

$ git remote rm origin

此处的“删除”其实是解除了本地和远程的绑定关系,并不是物理上删除了远程库。远程库本身并没有任何改动。要真正删除远程库,需要登录到Gitee,在后台页面找到删除按钮再删除。

分支管理

分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

创建与合并分支

在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支。

一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

在这里插入图片描述

每次提交,master分支都会向前移动一步。当创建分支的时候,比如创建一个dev分支,这时git新建了一个dev指针,指向的是master的提交,再把HEAD指向dev,就表示当前分支在dev上:<img src="git使用.assets/image-在这里插入图片描述

之后对工作区的修改和提交就是针对分支dev了,比如一次新的提交后,dev指针往前移动了一步,而master指针不变。
在这里插入图片描述

如果在dev上的工作完成了,需要进行合并,把dev合并到master上,git直接把master指向当前dev的提交就完成了合并:
在这里插入图片描述

合并完分之后,也可以删除dev分支,删除dev分支就是把dev的指针给删掉,删掉后,就只剩下master一条分支:
在这里插入图片描述

实际操作:

$ git checkout -b dev
Switched to a new branch 'dev'

git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

$ git branch dev
$ git checkout dev
Switched to branch 'dev'

然后,用git branch命令查看当前分支,该命令会展示出所有分支,

$ git branch
* dev
  master

然后在test.txt中新加一行create a new branch,然后提交。再切换回主分支,查看该文件中并没有新加的一行,这是因为刚才的改动知识在dev分支上改的,而master分支的提交点并没有变化。
在这里插入图片描述

然后可以将dev分支合并到master上,这时再查看文件就有了新增的那一行。

$ git merge dev
Updating 8fb43d3..f78d888
Fast-forward
 test.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

当然,也不是每次合并都能Fast-forward。合并完成后,如果不再需要dev分支,就可以删除dev分支了

$ git branch -d dev
Deleted branch dev (was f78d888).

再查看现有的分支,就只有master了

$ git branch
* master
分支命令总结

查看分支:git branch

创建分支:git branch <name>

切换分支:git checkout <name>或者git switch <name>

创建+切换分支:git checkout -b <name>或者git switch -c <name>

合并某分支到当前分支:git merge <name>

删除分支:git branch -d <name>

冲突

当两个分支同时对一个文件进行修改时,就可能会产生冲突。

新建一个分支dev1,然后将文件test.txt加上一行branch dev1 add,然后commit。

$ git checkout -b dev1
Switched to a new branch 'dev1'

然后切回到master分支,这时文件test.txt中并没有dev中新加的最后一行,在文件最后一行中加入master add,然后commit。

现在master和dev1分支中都有新的提交

在这里插入图片描述
这种情况下对分支进行合并就无法快速合并,产生了冲突

$ git merge dev1
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.

git告诉我们,test.txt文件存在冲突,必须手动解决冲突后再提交,通过git status也可以告诉我们冲突的文件:

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
        both modified:   test.txt

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

这时打开test.txt查看其内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lPtFVMp3-1665329449711)(git使用.assets/image-20220930210451406.png)]

git用<<<<<<<=======>>>>>>>标记出不同分支的内容,我们修改后保存

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git tracks changes of files.
create a new branch
master add
branch dev1 add

然后再进行提交就可以了,现在分支的情况就变为了
在这里插入图片描述

通过git log --graph命令可以查看到分支合并图
在这里插入图片描述

分支管理策略

通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。

如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。

$ git merge --no-ff -m "merge with no-ff" dev

合并dev分支,--no-ff参数,表示禁用Fast forward。因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

不使用Fast forward模式时,merge后为:

在这里插入图片描述

–no–ff用途

Git 合并两个分支时,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,叫做“快进”(fast-forward),比如下图:

 		  A---B---C feature
         /
D---E---F master

要把feature合并到master中,执行以下命令

$ git checkout master
$ git merge feature

结果变为

		  A---B---C feature
         /         master
D---E---F

因为 feature 就在 master 的下游,所以直接移动了 master 的指针,master 和 feature 都指向了 C。而如果执行了 git merge --no-ff feature 的话,是下面的结果:

   		  A---B---C feature
         /         \
D---E---F-----------G master

由于 --no-ff 禁止了快进,所以会生成一个新的提交,master 指向 G。

从合并后的代码来看,结果其实是一样的,区别就在于 --no-ff 会让 Git 生成一个新的提交对象.快进式合并会把 feature 的提交历史混入到 master 中,搅乱 master 的提交历史。所以如果你根本不在意提交历史,那么 --no-ff 其实没什么用。不过,如果某一次 master 出现了问题,你需要回退到上个版本的时候,比如上例,你就会发现退一个版本到了 B,而不是想要的 F,因为 feature 的历史合并进了 master 里。

分支策略

开发时,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
在这里插入图片描述

stash

git提供了git stash来进行暂存功能,主要用于以下情形:

  • 发现有一个类是多余的,想删掉它又担心以后需要查看它的代码,想保存它但又不想增加一个脏的提交。这时就可以考虑git stash
  • 使用git的时候,我们往往使用分支(branch)解决任务切换问题,例如,我们往往会建一个自己的分支去修改和调试代码, 如果别人或者自己发现原有的分支上有个不得不修改的bug,我们往往会把完成一半的代码commit提交到本地仓库,然后切换分支去修改bug,改好之后再切换回来。这样的话往往log上会有大量不必要的记录。其实如果我们不想提交完成一半或者不完善的代码,但是却不得不去修改一个紧急Bug,那么使用git stash就可以将你当前未提交到本地(和服务器)的代码推入到Git的栈中,这时候你的工作区间和上一次提交的内容是完全一样的,所以你可以放心的修Bug,等到修完Bug,提交到服务器上后,再使用git stash apply将以前一半的工作应用回来。
  • 经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是git stash命令。储藏(stash)可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用。
stash当前修改

git stash会把所有未提交的修改(包括暂存的和非暂存的)都保存起来,可以用于后续恢复。

在文件test.txt中加一行stash test,此时查看状态为:

$ git status
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:   test.txt

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

这时使用git stash将修改暂存下来,然后在查看状态

$ git stash
Saved working directory and index state WIP on master: ee11e7a conflict
$ git status
On branch master
nothing to commit, working tree clean

注意stash是本地的,不会通过git push命令上传到git server上。实际应用中推荐给每个stash加一个message,用于记录版本,使用git stash save取代git stash命令。示例如下:

$ git stash save "test-cmd-stash"

进行stash后,改动全部被暂存下来。并且文件变为修改之前的状态。

查看现有stash

通过git stash list可以查看已有的stash

$ git stash list
stash@{0}: WIP on master: ee11e7a conflict
恢复stash

一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除,后面可以跟着stash名字

另一种方式是用git stash pop,恢复的同时把stash内容也删了,这个指令将缓存堆栈中的第一个stash删除,并将对应修改应用到当前的工作目录下。

可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

$ git stash apply stash@{0}
查看指定stash的diff

可以使用git stash show命令,后面可以跟着stash名字。示例如下:

$ git stash show
 test.txt | 1 +
 1 file changed, 1 insertion(+)
$ git stash show stash@{0}
 test.txt | 1 +
 1 file changed, 1 insertion(+)

在该命令后面添加-p--patch可以查看特定stash的全部diff,如下:

$ git stash show stash@{0} -p
diff --git a/test.txt b/test.txt
index 05286a6..a91a6a9 100644
--- a/test.txt
+++ b/test.txt
@@ -4,4 +4,5 @@ Git tracks changes of files.
 create a new branch
 master add
 branch dev1 add
+stash test

从stash创建分支

如果你储藏了一些工作,暂时不去理会,然后继续在你储藏工作的分支上工作,你在重新应用工作时可能会碰到一些问题。如果尝试应用的变更是针对一个你那之后修改过的文件,你会碰到一个归并冲突并且必须去化解它。如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 git stash branch,这会创建一个新的分支,检出你储藏工作时的所处的提交,重新应用你的工作,如果成功,将会丢弃储藏。

$ git stash branch testchanges
Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      modified:   index.html
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   lib/simplegit.rb
#
Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)
暂存未跟踪或忽略的文件

默认情况下,git stash会缓存下列文件:

  • 添加到暂存区的修改(staged changes)
  • Git跟踪的但并未添加到暂存区的修改(unstaged changes)

但不会缓存一下文件:

  • 在工作目录中新的文件(untracked files)
  • 被忽略的文件(ignored files)

git stash命令提供了参数用于缓存上面两种类型的文件。使用-u或者--include-untracked可以stash untracked文件。使用-a或者--all命令可以stash当前目录下的所有修改。

cherry-pick

git cherry-pick命令的作用,就是将指定的提交(commit)应用于其他分支。

git cherry-pick <commitHash>

举例来说,代码仓库有master和feature两个分支。

a - b - c - d   Master
     \
       e - f - g Feature

现在将提交f应用到master分支。

切换到 master 分支

$ git checkout master

Cherry pick 操作

$ git cherry-pick f

上面的操作完成以后,代码库就变成了下面的样子。

 a - b - c - d - f   Master
     \
       e - f - g Feature

从上面可以看到,master分支的末尾增加了一个提交f。

git cherry-pick命令的参数,不一定是提交的哈希值,分支名也是可以的,表示转移该分支的最新提交。

$ git cherry-pick feature

上面代码表示将feature分支的最近一次提交,转移到当前分支。Cherry pick 支持一次转移多个提交。

$ git cherry-pick <HashA> <HashB>

上面的命令将 A 和 B 两个提交应用到当前分支。这会在当前分支生成两个对应的新提交。

如果想要转移一系列的连续提交,可以使用下面的简便语法。

// 不包含A,包含B
$ git cherry-pick A..B 

上面的命令可以转移从 A 到 B 的所有提交。它们必须按照正确的顺序放置:提交 A 必须早于提交 B,否则命令将失败,但不会报错。

注意,使用上面的命令,提交 A 将不会包含在 Cherry pick 中,即git cherry-pick (commitidA…commitidB]。如果要包含提交 A,可以使用下面的语法。

// 如果想搞成[]区间,使用 git cherry-pick A^..B 相当于[A B]包含A
$ git cherry-pick A^..B

多人协作

工作模式

多人协作的工作模式通常是这样:

  1. 首先,可以试图用git push origin <branch-name>推送自己的修改;
  2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
  3. 如果合并有冲突,则解决冲突,并在本地提交;
  4. 没有冲突或者解决掉冲突后,再用git push origin <branch-name>推送就能成功!

如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to <branch-name> origin/<branch-name>

常用命令
  • 查看远程库信息,使用git remote -v
  • 本地新建的分支如果不推送到远程,对其他人就是不可见的;
  • 从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
  • 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
  • 建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
  • 从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。

关于 git push和git origin的默认行为:https://segmentfault.com/a/1190000002783245

参考:

  1. liaoxuefeng.com

  2. https://www.liaoxuefeng.com/wiki/896043488029600

  3. https://gitee.com/help/articles/4120

  4. https://www.cnblogs.com/tocy/p/git-stash-reference.html

  5. https://blog.csdn.net/muzidigbig/article/details/122321393

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值