git实战指南

今天在往公司的gitlab上push项目的时候死活无法push上去,总是显示没有权限。报错信息上显示sshkey的问题,但是我在github上面都是好好的,搞了半天,我都翻出里git的配置文件改了好几遍都没有用,总之就是个垃圾。。。,后来我放弃了git协议,使用http协议手动认证身份就可以了。傻逼的错误信息如下:

1
2
3
4
5
6
sign_and_send_pubkey: signing failed: agent refused operation
Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

虽然体验不是很好但是用到了很多以前没有机会用的命令,实践出真知,今天就来总结一下实战中的git是怎么玩的。

安装

1
$ sudo apt install git

配置config

在终端直接输入以下命令:

1
2
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

这个一般我们安装好就会配置一下,这个是全局的配置,如果你的项目中没有自己的配置就会使用这个配置。关于git的配置,你可以用如下的命令查看都有那些信息:

1
$ git config -l

这会列出全局+当前目录下的git仓库的信息。如果你所在的目录不是个git仓库就只列出全局的配置信息。
当你不加-l的选项的时候,就会列出config常用的选项,其中有一些选项可以用来修改配置信息。这个当你需要用的时候自己在终端看一下就可以了。

其中也告诉我们,git的配置可以每个项目都有一个配置,这个配置就在你的仓库.git/文件夹下的config文件中。全局的配置在~/.gitconfig文件中。

ssh key

在终端生成一个ssh key的命令如下:

1
$ ssh-keygen -t rsa -C "e-mail@xxx.com"

生成的密钥和公钥在~/.ssh/文件夹下,你需要将你的后缀.pub的那个文件的内容复制出来,放到你的github或是公司的gitlab上。当然了,gitlab就算了吧,因为貌似不会起作用。

工作区 & 本地仓库 & 远程仓库

初学git的人往往分布清楚这几个的概念。那就画个图来说明一下简单直观。
(此处有图)

工作区

首先你要知道的是你写的文件,并不在git的概念中。啥意思呢,就是你写的文件就是你写的文件,git又不管你在这个文件夹下面写了什么东西,git的第一个空间是:工作区。当你将你的修改或是新写的文件通过git add的命令提交的时候这写文件才会被git记录下来,这时候是放到了工作区了。

既然是工作区,相对的自由度就大一些,你可以添加进去,然后当你要提交的时候觉得这个东西写的还不是很好,你想再继续开发一段时间再发布出去,这个时候你就可以使用 git checkout <文件>... 来丢弃工作区的改动。
相当于工作区放的都是你完成的产品,即将被发布。

本地仓库

当你觉得这次开发完成了,所有完成的作品也都放到工作区了。你就可以将整个工作区整体提交给本地仓库,使用如下命令:git commit -m 'say something'say something就是你在提交的时候简单的说一下这次你做了哪些东西。

仓库才是真正的git的领域,也是git的精髓所在,版本控制的集大成者。

一个仓库可以有很多个分支。这个分支是我们经常用到的,想比较而言,版本回退我们倒不是经常用到。什么时候会用版本回退呢?就是在我们发布的版本出现一些问题的时候,这个时候不能让一个有问题的东西给人用啊,所以就只好暂时版本回退到一个稳定版本,新功能暂时没有,不就没有问题了嘛!没错,程序员就是这样的逻辑,把报错信息删掉不就没有错误了嘛!
那么什么时候用分支呢?就是在开发的过程中嘛。多人协作,大家做的东西可能是不同的模块的,有的人做的模块可能要在未来的很多版本以后才能上线,这个时候总不能把自己的半成品也放到项目里发出去吧,所以干脆,你拉一个分支出去,等你开发结束了,再把这个分支合进主分支里好了。还有一些是什么情况呢?比如你开发到一定程度,接下来有两个方案,你不确定要做哪个,你可以都开发看看嘛,一般就是两波人。怎么办呢,两波人各拉一个分支出去,各自开发测试,等到开发完了,比较一下用哪个好,再合进主分支里发布。

关于git开发流的使用,有那么几个主流的使用方式,这个下次再补充进来。

本地仓库有很多分支喽,那么我这次提交要提交到哪个分支呢?

你当然要看一下当前有哪些分支喽:

1
2
3
4
5
$ git branch

# 结果如下:

* master

*号的分支就是你当前的默认分支,如果你不指明提交到哪个分支就是这个分支了。
master就是你建仓库时的主分支了。

你现在只有一个分支,突然这一刻你林纳斯灵魂附体,你有个绝佳的想法,于是你新建了一个分支要开发一个新的小功能,于是你就建了一个分支, 并把当前的默认分支改成了你的新分支,因为你觉得这个想法太棒了,你留着之前的那段代码只是为了纪念自己曾经傻逼过:

1
2
$ git branch Linux
$ git checkout Linux

一切行云流水的结束了,因为只是简单的两个命令而已。同时结束的当然还有林纳斯投错胎的灵魂附体,于是你看着这个新的分支陷入了沉思,不过并没有关系,这个伟大的名字并不能改变你的命运,毕竟你曾经傻逼过嘛,都是可以原谅的,于是你删掉了这个分支,继续傻逼下去:

1
$ git branch -D Linux

远程仓库

你可以看到有哪些远程仓库:

1
$ git remote

或是更详细看看,你从哪些仓库同步代码和向那些仓库推送变更:

1
$ git remote -v

你也可以看看有哪些远程分支:

1
2
3
4
5
6
7
8
$ git branch -a

# 结果如下:

* master
remotes/origin/HEAD -> origin/master
remotes/origin/developing
remotes/origin/master

remotes 就是远程分支, HEAD指明了这个远程仓库的当前分支是哪一个。
在下面有这个远程仓库的分支描述:remotes/仓库名/分支名

当然这个命令不报错是在你有远程仓库的前提下,如何建立远程仓库呢?别天真了,我怎么会告诉你呢?我也不会在本地建出来远程仓库,不过我会在远程建好了再建立连接。
先去github上建一个,反正没有钱搞gitlab这个垃圾。在建完仓库的页面中有一些提示的,其中有个这样的命令

1
$ git remote add origin git@git...

你可以用这个命令将本地仓库与这个远程仓库建立连接,其中origin是你给这个仓库起的名字,一般我们都是这个名字,毫无新意但是管用。

当然你也可以有多个远程仓库,就用上面这个命令就可以了,像个多面间谍一样向不同的仓库推送不同的代码。

注意啦!
怎么给不同的仓库推送不同的代码?如果你问了这个问题,说明你好像跟之前的我一样笨。
推送代码并不是仓库与仓库之间的行为,而是分支与分支的行为。

也就是说你可以推送本地的某个分支给远程的某个仓库的某个分支,用这个命令,很简单的:

1
$ git push -u origin master:developing

origin就是你要推的远程仓库,master是你本地的分支名,developingorigin仓库中的分支。如果不加冒号及后面的东西,就是推到目标远程仓库的默认当前分支。

这样这几个的关系应该就明白了。

本地如何优雅的使用git

经常用下面这个命令

1
$ git status

这会列出当前这个文件夹下你有哪些修改过的文件还没有add到工作区,有哪些文件是新的还没有add到工作区。。。
貌似就是这样了吧,再优雅的姿势我就不太会了。

如何解决问题哒?

git协议的连接转换成http协议的连接并没有相应的命令可以使用,我是找到了仓库文件夹下的.git/config文件,文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[remote "origin"]
url = http://gitlab.alibaba-inc.com/tair/xxxxxx.git
fetch = +refs/heads/*:refs/remotes/origin/*
[user]
email = bai@xxx.com
name = bai

将其中的urlgit协议链接改成了http协议的链接就可以了。

有冲突怎么办?

业界潜规则嘛,早提交的早下班,晚提交的改冲突。

push的时候发现跟上面版本不一致了,落后于远程的仓库,就得先同步下来。
当我们pull下来的时候,发现跟本地的内容有冲突。这个时候就会在本地的文件中多出许多标记,标记如下:

1
2
3
4
5
6
7
8
<<<< head

// 这里是你本地的内容
========

// 这里是远程pull下来的内容

>>>> 02XSFDDFDFA123A

手动合并,然后再pull。

错误的git pull怎么办

在你同步远端的时候,发现远端与你的不同太多,你需要新拉一个分支,保留自己目前的分支的时候,你需要回退到之前的某个版本。一般就会退到pull之间的版本,所以下面的命令:

git reset --hard HEAD

回退两个commit:

git reset --hard HEAD^

查看历史的commit记录,选择退到某个版本:
git log

上面命令中的HEAD 可以换成任何一个历史commit的编号ID。like this : 40a85d646d6f6b05bac2bf5ce2b9a1f44ed74d4d

Talk is not cheap.