【工具】Git入门学习

Git 入门学习

创建版本库

1
2
3
4
lzh@ubuntu:~/workspace$ mkdir learngit
lzh@ubuntu:~/workspace$ cd learngit
lzh@ubuntu:~/workspace/learngit$ pwd
/home/lzh/workspace/learngit

将目录 /home/lzh/workspace/learngit 初始化为一个仓库:

1
git init

这条命令会在当前目录下生成一个隐藏目录 .git

使用语句 git add git commit 来添加文件,和提交修改。

1
2
3
4
5
lzh@ubuntu:~/workspace/learngit$ git add readme.txt 
lzh@ubuntu:~/workspace/learngit$ git commit -m "add readme.txt"
[master (root-commit) f9ab921] add readme.txt
1 file changed, 1 insertion(+)
create mode 100644 readme.txt

git status 用于查看 git 当前的状态。

1
2
3
lzh@ubuntu:~/workspace/learngit$ git status
On branch master
nothing to commit, working tree clean

这表示没有需要提交的更改。我们修改一下 readme.txt 的内容,再查看一次:

1
2
3
4
5
6
7
8
9
10
lzh@ubuntu:~/workspace/learngit$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: readme.txt

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

git 告诉我们 readme.txt 被修改过了。我们可以通过 git diff 命令来查看它哪些地方被修改了:

1
2
3
4
5
6
7
8
9
10
11
12
lzh@ubuntu:~/workspace/learngit$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 1f45bc7..ebf599b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1 +1,2 @@
-it's a readme file.
\ No newline at end of file
+it's a readme file.
+Edit for the first time.
\ No newline at end of file

在了解了 readme.txt 被如何修改之后,再将它提交到仓库。提交修改和提交新文件的操作是相同的,即先 git addgit commit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
lzh@ubuntu:~/workspace/learngit$ git add readme.txt
lzh@ubuntu:~/workspace/learngit$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: readme.txt

lzh@ubuntu:~/workspace/learngit$ git commit -m "modify readme.txt"
[master 6cc166a] modify readme.txt
1 file changed, 2 insertions(+), 1 deletion(-)
lzh@ubuntu:~/workspace/learngit$ git status
On branch master
nothing to commit, working tree clean

版本回退

每次 commit ,就像是进行了一次快照。我们可以选择从一次 commit 中恢复。

使用 git log 查看:

1
2
3
4
5
6
7
8
9
10
11
12
13
lzh@ubuntu:~/workspace/learngit$ git log
commit 6cc166a21e5630e8d3a0151ee331c04c5ac2c251 (HEAD -> master)
Author: amjac <amjac_lzh@163.com>
Date: Sun Jan 5 23:35:38 2020 -0800

modify readme.txt

commit f9ab921e9c9c17eda1038254e0c893c9e0fbe451
Author: amjac <amjac_lzh@163.com>
Date: Sun Jan 5 23:19:58 2020 -0800

add readme.txt

在 git 中,HEAD 表示当前版本。现在我们将版本回退到上次 commit 的版本(用 HEAD^ 表示上个版本,HEAD^^ 表示上上个版本,HEAD~100 表示上 100 个版本。)

1
2
lzh@ubuntu:~/workspace/learngit$ git reset --hard HEAD^
HEAD is now at f9ab921 add readme.txt

此时再查看 git log:

1
2
3
4
5
6
7
lzh@ubuntu:~/workspace/learngit$ git log
commit f9ab921e9c9c17eda1038254e0c893c9e0fbe451 (HEAD -> master)
Author: amjac <amjac_lzh@163.com>
Date: Sun Jan 5 23:19:58 2020 -0800

add readme.txt

可以看到,之前的最新版本已经消失了。当然,只是显示中消失了。如果我们还能记得之前的 sha1 版本号,也可以强制恢复到之前的版本。例如,之前的版本是 6cc166a21e5630e8d3a0 ,可以用如下命令:

1
2
lzh@ubuntu:~/workspace/learngit$ git reset --hard 6cc166a21e5630e8d3a0
HEAD is now at 6cc166a modify readme.txt

当然,这样做必须记得之前版本的版本号。为了避免丢失这些信息,命令 git reflog 可以显示我们每次执行得命令:

1
2
3
4
5
lzh@ubuntu:~/workspace/learngit$ git reflog
6cc166a (HEAD -> master) HEAD@{0}: reset: moving to 6cc166a21e5630e8d3a0
f9ab921 HEAD@{1}: reset: moving to HEAD^
6cc166a (HEAD -> master) HEAD@{2}: commit: modify readme.txt
f9ab921 HEAD@{3}: commit (initial): add readme.txt

这样就能找到之前的版本号了。

合并多次 commit

git rebase

1
2
git rebase -i HEAD~4 # 对最近的4个commit进行rebase操作
git rebase -i 9fbf10 # 对 commit id 前几位为 9fbf10 的 commit 之后的 commit 进行 rebase

工作区和暂存区

Git 的独特之处在于有暂存区的概念。

工作区(Working Directory)

电脑中能看到的目录。比如 learngit 目录。

版本库(Repository)

工作区中的隐藏目录 .git 是版本库。版本库包含了很多内容,但最重要的是称为 stage 的暂存区,和 git 为我们自动创建的第一个分支 master,以及指向 master 的指针 HEAD。

git-repo

之前讲到,向 git 版本库中添加内容时,是分两步进行的:

  1. git add将文件修改添加到暂存区
  2. git commit将暂存区的所有内容提交到当前分支

即:需要提交的文件都放到暂存区中,然后一次性提交暂存区的所有修改。

测试一下:新建一个文件 LICENSE,再修改一下 readme.txt,然后查看 status

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
lzh@ubuntu:~/workspace/learngit$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <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 checkout -- filename 可以丢弃工作区的修改。

命令 git checkout -- readme.txt 的意思是,把 readme.txt 文件再工作区的修改全部撤销,这里有两种情况:

  1. readme.txt 被修改后,还没有被存放到暂存区,此时撤销修改就回到和版本库一摸一样的状态
  2. readme.txt 已经被添加到了暂存区,之后又作了修改,此时撤销修改就回到添加到暂存区之后的状态

总之,git checkout – 命令会让文件恢复到最近一次 git commit 或者 git add 时的状态。

注意,一定要用 git checkout -- ,没有 – 就会变成 切换到另一个分支

此外,已经提交到暂存区的修改也可以撤销。

当修改已经通过 git add 添加到暂存区时,可以使用 git reset 将暂存区的修改撤销掉,退回工作区。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
lzh@ubuntu:~/workspace/learngit$ git reset HEAD readme.txt
Unstaged changes after reset:
M readme.txt
lzh@ubuntu:~/workspace/learngit$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file: LICENSE

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: readme.txt


然后再用 git checkout 来撤销工作区的修改,退回版本库。

删除文件

在文件管理器中,将没用的文件删除,使用命令 rm 。但此时,工作区和版本库变得不一致了。git status 命令会告诉你哪些文件被删除了。

1
2
3
4
5
6
7
8
9
10
11
lzh@ubuntu:~/workspace/learngit$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

deleted: LICENSE
modified: readme.txt

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

git 显示,LICENSE 文件被删除了,此时有两个选择:

  1. git rm 命令删除,之后 git commit。这样,该文件就从版本库中被删除了。
  2. 删错了,用 git checkout -- LICENSE 来恢复。其实这就是用版本库里的版本来替换工作区里的版本。无论是工作区修改了还是删除,都可以一键还原。但是注意,只能从版本库中还原!!如果有未提交到版本库的修改,则无法修复。

创建分支与合并分支

可以创建分支,在分支上开发新功能,测试完成后再同步到 master 分支上。

创建名为 dev 的分支:

1
2
3
4
5
lzh@ubuntu:~/workspace/learngit$ git checkout -b dev
D LICENSE
M readme.txt
Switched to a new branch 'dev'

git checkout -b 表示创建分支并切换,其效果等同于下面两条命令:

1
2
git branch dev # 创建分支 dev
git checkout dev # 切换到分支 dev

使用 git branch 列出(当前分支有 *)

1
2
3
lzh@ubuntu:~/workspace/learngit$ git branch
* dev
master

然后进行一通操作。

切换回 master 分支,将 dev 分支的结果合并到 master 分支上:(git merge)

1
2
3
4
5
6
7
8
lzh@ubuntu:~/workspace/learngit$ git merge dev
Updating b480d9a..c8029f6
Fast-forward
LICENSE | 1 -
readme.txt | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
delete mode 100644 LICENSE

然后使用 git branch -d 删除分支 dev

1
2
3
4
lzh@ubuntu:~/workspace/learngit$ git branch -d dev
Deleted branch dev (was c8029f6).
lzh@ubuntu:~/workspace/learngit$ git branch
* master

切换分支也可以使用 git switch,例如:

1
2
git switch -c dev # 创建并切换到新分支 dev
git switch master # 切换到已有分支 master

解决分支合并时的冲突

???????

分支管理策略

通常,合并分支时,如果可能,Git 会用 fast forward 模式,此时删除分支后会丢失分支信息。(???删除了为什么不丢失?)

在执行 git merge 时,使用

1
git merge --no-ff -m "xxxxxxx" dev

这样可以把当前分支合并到 dev 分支的同时,生成一个 commit。

效果如下:

git-no-ff-mode