Loading

git 基础教程

git的两大特点

  • 版本控制:可以解决多人同时开发的代码问题,也可以解决找回历史代码的问题。
  • 分布式:Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。

安装与配置

sudo apt-get install git

创建一个版本库

新建一个目录git-test,在git-test目录下创建一个版本库,命令如下

mkdir git-test
cd git-test
git init

可以看到在git_test目录下创建了一个.git隐藏目录,这就是版本库目录。

版本创建与回退

使用

在git-test目录下创建一个文件code.txt,编辑内容如下:

this is the first line

使用如下两条命令可以创建一个版本:

git add code.txt
git commit -m '版本1'

使用如下命令可以查看版本记录:

git log

commit 731af4c679dd4304d26820f02dc2874921f1ee6d (HEAD -> master)
Author: ''
Date:   Tue Mar 22 10:33:44 2022 +0800

    版本1

继续编辑code.txt,在里面增加一行,内容如下:

this is the second line

使用如下命令再创建一个版本并查看版本记录:

git add code.txt
git commit -m '版本2'
git log

commit 2b62bbe9cefe48f200946ec1567763f0c677d0ef (HEAD -> master)
Author: ''
Date:   Tue Mar 22 10:39:20 2022 +0800

    版本2

commit 731af4c679dd4304d26820f02dc2874921f1ee6d
Author: ''
Date:   Tue Mar 22 10:33:44 2022 +0800

    版本1

现在若想回到某一个版本,可以使用如下命令:

git reset --hard HEAD^

其中HEAD表示当前最新版本,HEAD表示当前版本的前一个版本,HEAD^表示当前版本的前前个版本,也可以使用HEAD1表示当前版本的前一个版本,HEAD100表示当前版本的前100版本。
执行上述命令后查看code.txt中的内容如下:

git log

commit 731af4c679dd4304d26820f02dc2874921f1ee6d (HEAD -> master)
Author: ''
Date:   Tue Mar 22 10:33:44 2022 +0800

    版本1
cat code.txt

this is the first line

执行命令后使用git log查看版本记录,发现现在只能看到版本1的记录,cat code.txt查看文件内容,现在只有一行,也就是第一个版本中code.txt的内容。
假如我们现在又想回到版本2,这个时候怎么办?可以使用如下命令:

git reset --hard 版本号

假如说没有记录之前版本2的版本号,该怎么办?使用如下命令:

git reflog

731af4c (HEAD -> master) HEAD@{0}: reset: moving to HEAD^
2b62bbe HEAD@{1}: reset: moving to 2b62bbe9cefe48f200946ec1567763f0c677d0ef
731af4c (HEAD -> master) HEAD@{2}: reset: moving to HEAD^
2b62bbe HEAD@{3}: commit: 版本2
731af4c (HEAD -> master) HEAD@{4}: commit (initial): 版本1

从上面可以看到版本2的版本号为:2b62bbe
执行如下命令:

git reset --hard 2b62bbe
git log

commit 2b62bbe9cefe48f200946ec1567763f0c677d0ef (HEAD -> master)
Author: ''
Date:   Tue Mar 22 10:39:20 2022 +0800

    版本2

commit 731af4c679dd4304d26820f02dc2874921f1ee6d
Author: ''
Date:   Tue Mar 22 10:33:44 2022 +0800

    版本1

此时版本2又回来了。

工作区和暂存区

工作区(Working Directory)

电脑中的目录,比如我们的git-test,就是一个工作区。

版本库(Repository)

工作区有一个隐藏目录.git,这个不是工作区,而是git的版本库。git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
因为我们创建git版本库时,git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。
版本库示意图
前面讲了我们把文件往git版本库里添加的时候,是分两步执行的:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
下面在git-test目录下再创建一个文件code2.txt,然后编辑内容如下:

the code2 first line

然后再次编辑code.txt内容,在其中加入一行,编辑后内容如下:

this is the third line

使用如下命令查看当前工作树的状态:

git status

位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     code.txt

未跟踪的文件:
  (使用 "git add <文件>..." 以包含要提交的内容)
	code2.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

使用如下命令把code.txt和code2.txt加入到暂存区,然后再执行git status命令,结果如下:

git add code2.txt
git add code.txt
git status

位于分支 master
要提交的变更:
  (使用 "git restore --staged <文件>..." 以取消暂存)
	修改:     code.txt
	新文件:   code2.txt

git add命令是把所有提交的修改存放到暂存区。执行git commit就可以一次性把暂存区的所有修改提交到分支创建一个版本。

git commit -m '版本3'
git log

commit 909b1e9a0ece54abac9c3304883e8df6e0d565c7 (HEAD -> master)
Author: NeYoXXX <640667912@qq.com>
Date:   Tue Mar 22 11:19:33 2022 +0800

    版本3

commit 2b62bbe9cefe48f200946ec1567763f0c677d0ef
Author: NeYoXXX <640667912@qq.com>
Date:   Tue Mar 22 10:39:20 2022 +0800

    版本2

commit 731af4c679dd4304d26820f02dc2874921f1ee6d
Author: NeYoXXX <640667912@qq.com>
Date:   Tue Mar 22 10:33:44 2022 +0800

    版本1

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

git status

位于分支 master
无文件要提交,干净的工作区

上述执行流程图

管理修改

git管理的文件的修改,只会提交暂存区的修改来创建版本

  • 编辑 code.txt 添加一行 this is the forth line,并使用 git add 命令将其添加到暂存区中;
  • 再继续编辑 code.txt ,并在其中增加一行 this is the new line
  • git commit 创建一个版本,并使用 git status 查看,发现第二次修改 code.txt 内容之后(this is the new line 内容),并没有将其添加的工作区,所以创建版本的时候并没有被提交。
git commit -m '版本4'
git status

位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     code.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

撤销修改

可以使用git restore或者git checkout --来丢弃工作区的修改,如下:

git restore code.txt
git status

位于分支 master
无文件要提交,干净的工作区

继续编辑 code.txt,并在其中添加一行the new line,并将其添加的暂存区。

git status

位于分支 master
要提交的变更:
  (使用 "git restore --staged <文件>..." 以取消暂存)
	修改:     code.txt

可以使用 git restore --staged <文件> 或者git reset HEAD <文件>取消暂存

git restore --staged code.txt
git status

位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     code.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a"

对比文件的不同

对比工作区和某个版本中文件的不同

现在要对比工作区中 code.txt 和HEAD版本中 code.txt 的不同。使用如下命令:

git diff HEAD -- code.txt

diff --git a/code.txt b/code.txt
index 66f9219..324317f 100644
--- a/code.txt
+++ b/code.txt
@@ -2,3 +2,4 @@ this is the first line
 this is the second line
 this is the third line
 this is the forth line
+the new line

对比两个版本间文件的不同

现在要对比HEAD和HEAD^版本中code.txt的不同,使用如下命令:

git diff HEAD HEAD^ -- code.txt

diff --git a/code.txt b/code.txt
index 66f9219..01e1274 100644
--- a/code.txt
+++ b/code.txt
@@ -1,4 +1,3 @@
 this is the first line
 this is the second line
 this is the third line
-this is the forth line

删除文件

rm code2.txt
git status

位于分支 master
尚未暂存以备提交的变更:
  (使用 "git add/rm <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	删除:     code2.txt

修改尚未加入提交(使用 "git add" 和/或 "git commit -a")

这个时候,git知道删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻提示哪些文件被删除了。现在有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit;另一种情况是删错了,可以直接使用git checkout – code2.txt,这样文件code2.txt又回来了。

命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么永远不用担心误删,但是要小心,只能恢复文件到最新版本,会丢失最近一次提交后你修改的内容。

分支管理

创建与合并分支

git把之前每次提交的版本串成一条时间线,这条时间线就是一个分支。截止到目前只有一条时间线,在git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
一开始的时候,master分支是一条线,git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:
image
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长。
当我们创建新的分支,例如dev时,git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
image
git创建一个分支很快,因为除了增加一个dev指针,改变HEAD的指向,工作区的文件都没有任何变化。
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
image
假如我们在dev上的工作完成了,就可以把dev合并到master上。git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
image
git合并分支也很快,就改改指针,工作区内容也不变。
合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:
image

实际操作

执行如下命令可以查看当前有几个分支并且看到在哪个分支下工作。

git branch

* master

创建一个分支dev并切换到其上进行工作。

git checkout -b dev
git branch

* dev
  master

修改code.txt内容,在里面添加一行add one line(如果工作区有未暂存的内容请先清除),并进行提交。

git add code.txt
git commit -m 'dev分支提交'
git log

commit 6aa071a738dbbf56e7c1dd00e1a6b74c7b8eeaa1 (HEAD -> dev)
Author: NeYoXXX <640667912@qq.com>
Date:   Tue Mar 22 12:19:29 2022 +0800

    dev分支提交

commit a0fb152408675f48277769123564b8e96d8a3512 (master)
Author: NeYoXXX <640667912@qq.com>
Date:   Tue Mar 22 11:32:31 2022 +0800

    版本4
......

dev分支的工作完成,就可以切换回master分支:

git checkout master
git branch

  dev
* master

查看code.txt,发现添加的内容没有了。因为那个提交是在dev分支上,而master分支此刻的提交点并没有变。
现在,我们把dev分支的工作成果合并到master分支上:

git merge dev

更新 a0fb152..6aa071a
Fast-forward
 code.txt | 1 +
 1 file changed, 1 insertion(+)

git merge命令用于合并指定分支到当前分支。合并后,再查看code.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。
注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
合并完成后,就可以放心地删除dev分支了,删除后,查看branch,就只剩下master分支了。

git branch -d dev

已删除分支 dev(曾为 6aa071a)。

解决冲突

安装上面的方法再创建一个新分支dev;修改code.txt内容,并进行提交;切换回master分支;在master的code.txt添加一行内容并进行提交。现在,master分支和dev分支各自都分别有新的提交,变成了这样:
image
这种情况下,git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突。
执行merge命令尝试将dev分支合并到master分支上来。git告诉我们,code.txt文件存在冲突,必须手动解决冲突后再提交。

git merge dev

[master 24d31a4] master提交
 1 file changed, 1 insertion(+)
hanzhixindeMBP:git-test hanzhixin$ git merge dev
自动合并 code.txt
冲突(内容):合并冲突于 code.txt
自动合并失败,修正冲突然后提交修正的结果。

git status也可以告诉我们冲突的文件:

git status

位于分支 master
您有尚未合并的路径。
  (解决冲突并运行 "git commit")
  (使用 "git merge --abort" 终止合并)

未合并的路径:
  (使用 "git add <文件>..." 标记解决方案)
	双方修改:   code.txt

查看code.txt的内容:

this is the first line
this is the second line
this is the third line
this is the forth line
add one line
<<<<<<< HEAD
maste add one liner
=======
dev add one line
>>>>>>> dev

git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,修改如下:

this is the first line
this is the second line
this is the third line
this is the forth line
add one line
maste add one liner
dev add one line

再提交。现在,master分支和dev分支变成了下图所示:
image
用带参数的git log也可以看到分支的合并情况:

git log --graph --pretty=oneline

*   03830e9cd9dd80efa1c1726d6334eee88f74195d (HEAD -> master) 解决冲突
|\
| * 876fb167755e4a96e0c4e78d530ebbff1e98ea47 (dev) dev提交
* | 24d31a4efe92ee1fcf42228dc2018da01599296d master提交
|/
* 6aa071a738dbbf56e7c1dd00e1a6b74c7b8eeaa1 dev分支提交
* a0fb152408675f48277769123564b8e96d8a3512 版本4
* 909b1e9a0ece54abac9c3304883e8df6e0d565c7 版本3
* 2b62bbe9cefe48f200946ec1567763f0c677d0ef 版本2
* 731af4c679dd4304d26820f02dc2874921f1ee6d 版本1

最后工作完成,可以删除dev分支。

分支管理策略

通常,合并分支时,如果可能,git会用fast forward模式,但是有些快速合并不能成而且合并时没有冲突,这个时候会合并之后并做一次新的提交。但这种模式下,删除分支后,会丢掉分支信息。

  • 创建切换到dev分支下。
  • 新建一个文件code3.txt编辑内容如下,并提交一个commit。git commit -m '创建文件code3.txt'
  • 切换回master分支,编辑code.txt并进行一个提交。git commit -m '添加新行'
  • 合并dev分支的内容到master分支。git merge dev
  • 出现如下提时,这是因为这次不能进行快速合并,所以git提示输入合并说明信息,输入之后合并内容之后git会自动创建一次新的提交。
Merge branch 'dev'
# 请输入一个提交信息以解释此合并的必要性,尤其是将一个更新后的上游分支
# 合并到主题分支。
#
# 以 '#' 开始的行将被忽略,而空的提交说明将终止提交。
  • 使用分支命令查看分支信息。
git log --pretty=oneline --graph

*   24c5c2fb731c1db01befc0b5a100c9d5b6b04286 (HEAD -> master) Merge branch 'dev'
|\
| * 998ab3038ba20782d2fd1c6eb8d5a2a2d3be826a (dev) 创建文件code3.txt
* | 335776ebd40538e3c5da6f18d53c5051a4f3979f 添加新行
* |   03830e9cd9dd80efa1c1726d6334eee88f74195d 解决冲突
|\ \
| |/
| * 876fb167755e4a96e0c4e78d530ebbff1e98ea47 dev提交
* | 24d31a4efe92ee1fcf42228dc2018da01599296d master提交
|/
* 6aa071a738dbbf56e7c1dd00e1a6b74c7b8eeaa1 dev分支提交
* a0fb152408675f48277769123564b8e96d8a3512 版本4
* 909b1e9a0ece54abac9c3304883e8df6e0d565c7 版本3
* 2b62bbe9cefe48f200946ec1567763f0c677d0ef 版本2
* 731af4c679dd4304d26820f02dc2874921f1ee6d 版本1
  • 删除dev分支。git branch -d dev

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

  • 创建并切换到dev分支。
  • 修改code.txt内容,并提交一个commit。
  • 切换回master分支。
  • 准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward:
git merge --no-ff -m '禁用fast-forward合并' dev

因为本次合并要创建一个新的commit,所以加上-m参数,把commit描述写进去。

  • 合并后,我们用git log看看分支历史:可以看到,不使用Fast forward模式,merge后就像这样:
*   68bf69276c1b9bced38092f7068f995f11f5b7a6 (HEAD -> master) 禁用fast-forward合并
|\
| * 9145fb6b995a4925baed118c42e19e6457bc1b22 (dev) dev添加新行
|/
*   24c5c2fb731c1db01befc0b5a100c9d5b6b04286 Merge branch 'dev'
|\
| * 998ab3038ba20782d2fd1c6eb8d5a2a2d3be826a 创建文件code3.txt
* | 335776ebd40538e3c5da6f18d53c5051a4f3979f 添加新行
* |   03830e9cd9dd80efa1c1726d6334eee88f74195d 解决冲突
|\ \
| |/
| * 876fb167755e4a96e0c4e78d530ebbff1e98ea47 dev提交
* | 24d31a4efe92ee1fcf42228dc2018da01599296d master提交
|/
* 6aa071a738dbbf56e7c1dd00e1a6b74c7b8eeaa1 dev分支提交
* a0fb152408675f48277769123564b8e96d8a3512 版本4
* 909b1e9a0ece54abac9c3304883e8df6e0d565c7 版本3
* 2b62bbe9cefe48f200946ec1567763f0c677d0ef 版本2
* 731af4c679dd4304d26820f02dc2874921f1ee6d 版本1

image

Bug分支

软件开发中,bug就像家常便饭一样。有了bug就需要修复,在git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。
当你接到一个修复一个代号001的bug的任务时,很自然地,你想创建一个分支bug-001来修复它,但是,等等,当前正在dev上进行的工作还没有提交:

git status

位于分支 dev
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     code.txt

并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

git stash

保存工作目录和索引状态 WIP on dev: 9145fb6 dev添加新行

首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:

git checkout master
git checkout -b bug-001

现在修复bug,把修改第一行 this is the first line (修复bug) ,然后提交。
修复完成后,切换到master分支,并完成合并,最后删除bug-001分支。
现在bug-001修复完成,是时候接着回到dev分支干活了!工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:

git status
git stash list

stash@{0}: WIP on dev: 9145fb6 dev添加新行

作现场还在,git把stash内容存在某个地方了,但是需要恢复一下.

git stash pop

位于分支 dev
尚未暂存以备提交的变更:
  (使用 "git add <文件>..." 更新要提交的内容)
  (使用 "git restore <文件>..." 丢弃工作区的改动)
	修改:     code.txt

使用github

创建仓库

  • 注册github账户,登录后,点击"New respository "
  • 在新页面中,输入项目的名称,勾选'readme.md',点击'create repository'
    image
  • 添加成功后,转到文件列表页面
    image

添加ssh账户

点击账户头像后的下拉三角,选择'settings',如果某台机器需要与github上的仓库交互,那么就要把这台机器的ssh公钥添加到这个github账户上,点击'SSH and GPG keys',添加ssh公钥。
image
回到用户的主目录下,编辑文件.gitconfig,修改某台机器的git配置;修改为注册github时的邮箱,填写用户名。

cd ~
cat .gitconfig

[user]
	password = 123456
	name = XXX
	email = 123456789@qq.com
[http]
	sslVerify = false

使用如下命令生成ssh密钥。

ssh-keygen -t rsa -C "邮箱地址"

进入主目录下的.ssh文件件,下面有两个文件。

cd ~/.ssh/
ls

id_rsa		id_rsa.pub	known_hosts

公钥为 id_rsa.pub,私钥为 id_rsa,复制公钥的内容到github上,如下:
image

克隆项目

在浏览器中点击进入github首页,再进入项目仓库的页面,复制git地址

git clone '项目地址'

克隆出错

eval "$(ssh-agent -s)"
ssh-add

上传分支

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

git push origin 分支名称(本地分支)

将本地分支跟踪服务器分支

git branch --set-upstream-to=origin/远程分支名称 本地分支名称
例:
git branch --set-upstream-to=origin/dev dev

从远程分支上拉取代码

git pull orgin 分支名称

使用上述命令会把远程分支smart上的代码下载并合并到本地所在分支。

Git 补充

本地初始化仓库,并与github关联,

  1. 建立本地仓库 git init 初始化
  2. git add .
  3. git commit -m “update”
  4. 在github网页,创建github仓库
  5. 关联仓库 git remote add origin 地址
  6. git push -u origin master
  7. 刷新github网页,已上传完成

推荐阅读

https://www.ruanyifeng.com/blog/2014/06/git_remote.html
https://www.liaoxuefeng.com/wiki/896043488029600

posted @ 2022-03-23 12:17  _尼欧`  阅读(265)  评论(0编辑  收藏  举报