Git基本使用和个人排错日志(持续更新)

Git基本使用和个人排错日志(持续更新)

git是一个日常使用最多的版本控制工具,对于个人开发者来说,掌握基本使用是非常重要的。本篇将简单介绍git的基本使用指令,以及个人在开发中遇到一些有关git的问题。

Git基本使用

1. 初始化版本库

git init

到你的项目根目录中去,随便打开一个命令行窗口(cmd,bash,powershell都行),本地先做一个初始化。这条指令执行之后,会在当前目录下产生一个.git的文件夹(默认情况下是隐藏的),里头主要负责记录你的文件修改和版本控制信息的,不要轻易去改动它。

2.代码更新

git add <filename>
git add .

git commit -m "msg"

其实这样就已经可以开始正常使用git了,虽然目前还局限于本地。挨个说说吧,git add是将本次的更新的添加到本地仓库的缓存,如果不想将此次更新全部都添加,那么就可以在后面加上文件名(后缀也添上)。

git add还不算将更新提交到了代码仓库,要想添加到本地仓库,我们还需要使用git commit命令。-m后面需要跟着本次提交所附带的文字注释,比如:

git add . #全部提交
git commit -m "第一版"

3.连接远程

接下来我们终于就想要提交到远程仓库(github,gitee等)了,我们首先需要连接到远程仓库(确保在此之前,你已经在github/gitee上建了一个空仓库)

git remote add <name> <address>

name是为你目前的项目取一个git语境下的别名(从这个语境出发,我们之后会讲到分支branch),address就是远程仓库的地址(主要的代码仓库中心通常会提供webURL,也就是xxx.git),比如:

git remote add origin https://github.com/JackVictor/git_basis.git

如果想查看你已经配置的远程仓库服务器,可以运行 git remote 命令。 它会列出你指定的每一个远程服务器的简写。你也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。

$ git remote -v
origin https://github.com/JackVictor/git_basis.git (fetch)
origin https://github.com/JackVictor/git_basis.git (push)

add了,commit了,连接了远程仓库,那么现在我们就可以将本地的代码更新push到远程了吗?还不能,我们还需要配置自己在远程仓库的账号,你可以做自己的项目觉得没什么,但是负责开源项目的人可不希望有个pusher是个无名氏/透明人(你也做不到这样)!

git config --global user.name "John Doe"
git config --global user.email johndoe@example.com #两个选其一就好
# 之后会让你输密码

连接成功之后,我们最好再进行一条指令,目前它旨在保证在初始状态远程仓库的代码和本地的代码,版本都是一致的最新状态。

git pull #主要功能是:将远程版本库的修改并入当前分支。 如果当前分支落后于远程分支,那么默认情况下,它将快速合并当前分支以匹配远程分支。 

好了,接下来我们终于可以push了。

git push <name> <branch>

name就是在git语境下为你当前的项目取的别名,branch就是要推送的目标分支。如果提示报错,不妨加上--set-upstream可选项:

git push --set-upstream origin master #例子。将当前的版本更新推送到origin项目当中的master分支

4.版本回溯

此前我们已经简单过了一遍git提交代码的流程,但目前看来,时序一直是向前的,版本似乎一直都只能往前走而不能往回倒,这算什么“版本控制”呢?因此,为了展现git”回到过去“的能力,这一小节我们简单说一说git有关版本回溯的一些知识。

为了便于理解,这里咱不关乎远程分支,只讲本地上单分支的版本回溯。

实际上,连接了远程的git版本控制也比较好做,直接去到你远程仓库的网页上,就可以看到所有的历史提交记录。想要回溯到某个版本,只需要点击几下鼠标就可以了。

git log

想要版本回溯,我们总要先知道回溯到哪个版本吧?这条指令能告诉我们每一次的本地提交记录,commit后面紧跟的就是版本号,如下图:

git log <versioon>

指令后面添上版本号就能看到更详细的提交记录,这就考虑到一个项目开始周期长了,自己都不清楚以前写了啥。。。

git reset --hard <version>

确定好了要回溯的版本,我们就执行这条指令。--hard这个选项,如果你想要连索引和工作树都一起重置,就最好加上,因为git reset指令默认会选择--mixed——只重置索引,不重置工作树。

怎么突然多出了索引工作树这两个概念?瞬间就有点懵?其实,索引工作树这两个概念只是为了方便描述从本地文件修改git commit的两个阶段的提交,一点儿不玄乎,我们直接放一张图:

因此,我们可以简单说:

  • 工作树:就是本地修改,直观来看,就是你现在在自己电脑上看到的一切
  • 索引:所有git add之后的修改

现在,我们就皮那么一下,就是只执行git reset <version>,默认以--mixed来回溯,会发生什么:

我们发现,现在所看到的,仍然是第三版,没有回溯到第一版!但对于git,它已经完成了回溯的任务,我们使用git log来看一下到目前为止的提交记录,发现git成功回到了过去,记录只剩下了最初第一版!

那么问题就很明显了,git完成了它的任务,只是我们本地没有来得及修改,因此加上--hard选项,方可和git保持一致。

git reflog

git真的相当照顾手残党了,如果说正常提交更新还可以有git reset来补救失误,那么这条指令就相当于第二颗后悔药。它的作用是找回丢失的提交。因为在前面我们展示了,一旦我们从现在的版本v3,选择了回溯到过去的某个版本v1,那么发生在v1后的所有版本(在本例中是v2,v3)都将丢失!

这样的丢失代偿可能有点巨大。我们继续本例的实验,现在我们的版本是v1,执行git reflog指令,得到:

很惊喜吧!丢失的提交版本都回来了,我们选择相应的版本号,就能立即回溯!

5.分支与合并

前面我们所讲的都是单分支的版本控制,这对一些小型的单体项目个人开发也许还比较适用。然而,面对更加常见的团队开发项目,我们就必须弃用这种单分支的方案了。因为我们设想,一个分支就相当于一个开发模块,要想充分利用人力资源,并加快开发效率,我们肯定会将团队分作几个部门,各部门分管各个单独的开发模块,也对应着各个单独的开发模块,然后并行地进行开发任务/版本迭代,最后才将所有的分支合并为一个分支,完成项目交付。

那么在git当中,为了实现这个目的,就有了对应的分支和合并指令。我们先讲分支(branch):

git branch <new_branch> <main_branch>

这条指令的作用是从main_branch分支上创建new_branch分支。倘若这两个选项都不写,那就默认列出当前所有分支。如下,基于main分支,我已经创建了两条分支(绿色字体表明此分支为当前分支):

git switch <branch>

而使用这条指令可以让我们的工作树灵活地切换到指定的分支。

既然可以创建分支,那就必然可以删除分支。而对于删除,这里有两种:

git branch -d -r <origin/todo>  #删除远程跟踪的分支
git branch -D <branch> #删除本地分支

这里我们尝试下第二种:

在每个单独的分支上,我们都可以进行先前所讲过的所有操作(代码更新,连接远程,版本回溯等等…….),这个就不多废话了。值得注意的是,当我们创建了新的分支,并且还连接了远程,这时我们就不光需要知道当前分支的状态了,其他分支是什么个情况,我们也应该了解。使用git log打印日志后,我们会发现每一个分支最顶端的版本号后都跟着一个描述:

这里的HEAD本身是一个引用,指向的是当前用户工作树所在的分支,通俗点,就是告诉你现在在哪个分支下coding。

这三种描述信息在IDEA的图形化Git中。有各自的对应:

  • 黄色:本地分支中当前所在的地方
  • 绿色:本地各个分支所处的版本
  • 紫色:远程各个分支所处的版本

以上就是分支的基本指令,接下来我们讲讲合并(merge)

git merge <branch>

作用很简单,它将指定的提交内容(从它们的历史与当前分支相分离时起)并入当前分支。如下图所示(图源:git documentation):

这个合并成功后的版本,之后会一直存留在发起merge的那一方分支(在本例中,合并产生的新版本会保留在master分支上)。然而,在使用merge的时候,必须格外小心注意,因为即便在项目开发前已经做i好了统筹与分析,不同分支要想合并在一块多多少少还是会出现冲突。

而可能出现冲突的有关情况,大致有以下几种:

  1. 同一文件的同一行被不同分支修改
    • 如果两个分支在同一个文件的同一行进行了不同的修改,Git 无法确定哪一个修改应该保留。
  2. 一个分支中删除了文件,而另一个分支中修改了该文件
    • 如果一个分支删除了文件,而另一个分支修改了该文件,Git 无法自动决定是删除文件还是保留修改。
  3. 文件重命名冲突
    • 如果两个分支分别将同一个文件重命名为不同的名字,Git 无法决定使用哪个名字。

当真的出现冲突了,git就会首先选择能否自动处理合并,如若不能,就会让我们开发者手动处理。这里建议,使用VScode或者其他UI界面良好的IDE来处理合并冲突会比较好——自带编辑器的它们,一是观看差异方便,二是修改代码也更加容易。

随着分支的增加,以及合并次数的增多,整个版本迭代历史就会变得越来越复杂,这时我们就可以通过下面这条指令,以图形化的方式打印出所有的迭代历史以及彼此之间的关系,这有助于我们理顺整个或局部的迭代历史。

git log --graph

Git的个人排错日志

push之前先pull以保证代码提交的时序性

需要注意的是,在你上次pull代码之后到你现在要push代码之前,如果有其他人向你的远程仓库push了代码,那么当你在push的时候就要先用pull代码重新把远程仓库的代码拉下来,然后重新git add 、git commit后才能push。

事故现场

git pull 报错:error: Pulling is not possible because you have unmerged files.

报错:

$ git pull
error: Pulling is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use ‘git add/rm <file>’
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
 

翻译过来:

错误:无法提取,因为您有未合并的文件。

提示:在工作树中修复它们,然后使用“git add/rm<file>”

提示:根据需要标记解决方案并提交。

致命:由于未解决的冲突而退出。

解决方法:

提示了先提交

git add.git commit -m "xxx"
git pull origin master
git add .
git commit -m "xxx"
git push origin master

不要双开代理,可能会导致远程操作失败

这个意思是说,如果你已经在本地开启了代理,就不需要再给git配置代理了;反之,git配置代理之后,本地就不需要配了——也就是不能有“双重代理”的意思。否则,有关远程的所有操作都有可能失败。

报错信息:

fatal: unable to access ‘https://github.com/JackVictor1027/CS_self_learning.git/‘: Failed to connect to github.com port 443 after 21063 ms: Couldn’t connect to server

解决办法:

最好就是开着本地代理,把git的代理取消了。因为我们的本地代理要负责不只有git:

git config --global --unset http.proxy
git config --global --unset https.proxy

参阅

https://git-scm.com/docs

https://blog.csdn.net/ZTZY520/article/details/54023395

Comments

No comments yet. Why don’t you start the discussion?

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注