Git 原理与使用

打印 上一主题 下一主题

主题 891|帖子 891|积分 2673

一、基本操纵

1.1、Git安装

centos安装:

 centos7.6为例:
  1. sudo yum -y install git
复制代码
 检察 Git 安装的版本:
  1. git --version
复制代码


ubuntu安装:

 ubuntu20.04为例:
  1. sudo apt-get install git -y
复制代码
检察 git 安装的版本:
  1. git --version
复制代码

1.2、Git 基本操纵

创建 Git 本地堆栈

堆栈是进⾏版本控制的⼀个⽂件⽬录,创建⼀个 Git 本地堆栈对应的命令为 git init ,留意命令要在⽂件⽬录下执⾏,比方:
  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ pwd
  2. /home/ketil/gitcode
  3. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git init
  4. Initialized empty Git repository in /home/ketil/gitcode/.git/
  5. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ ll -a
  6. total 12
  7. drwxrwxr-x 3 ketil ketil 4096 Oct  8 18:27 ./
  8. drwxr-x--- 9 ketil ketil 4096 Oct  8 18:27 ../
  9. drwxrwxr-x 8 ketil ketil 4096 Oct  8 18:27 .git/
复制代码
当前⽬录下多了⼀个 .git 的隐蔽⽂件, .git ⽬录是 Git 来跟踪管理堆栈的。
  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ tree .git
  2. .git/
  3. ├── branches
  4. ├── config
  5. ├── description
  6. ├── HEAD
  7. ├── hooks
  8. │   ├── applypatch-msg.sample
  9. │   ├── commit-msg.sample
  10. │   ├── fsmonitor-watchman.sample
  11. │   ├── post-update.sample
  12. │   ├── pre-applypatch.sample
  13. │   ├── pre-commit.sample
  14. │   ├── pre-merge-commit.sample
  15. │   ├── prepare-commit-msg.sample
  16. │   ├── pre-push.sample
  17. │   ├── pre-rebase.sample
  18. │   ├── pre-receive.sample
  19. │   └── update.sample
  20. ├── info
  21. │   └── exclude
  22. ├── objects
  23. │   ├── info
  24. │   └── pack
  25. └── refs
  26. ├── heads
  27. └── tags
  28. 9 directories, 16 files
复制代码


配置 Git

当安装 Git 后⾸先要做的事变是设置用户名称e-mail地点。配置命令为:
  1. git config [--global] user.name "Your Name"
  2. git config [--global] user.email "email@example.com"
  3. # 把 Your Name 改成你的昵称
  4. # 把 email@example.com 改成邮箱的格式,只要格式正确即可。
复制代码
此中 --global 是⼀个可选项。如果使⽤了该选项,表⽰这台呆板上全部的 Git 堆栈都会使⽤这个配置。要留意的是,执⾏命令时必须要在堆栈⾥。
检察配置命令为:
  1. git config -l
复制代码
删除对应的配置命令为:
  1. git config [--global] --unset user.name
  2. git config [--global] --unset user.email
复制代码

⼯作区、暂存区、版本库



  • ⼯作区:是在电脑上要写代码或⽂件的⽬录。
  • 暂存区:英⽂叫 stage 或 index。⼀般存放在 .git ⽬录下的 index ⽂件(.git/index)中,偶然把暂存区偶然也叫作索引(index)。
  • 版本库:⼜名堆栈,英⽂名 repository 。⼯作区有⼀个隐蔽⽬录 .git ,它不算⼯作区,⽽是 Git 的版本库。这个版本库⾥⾯的全部⽂件都可以被 Git 管理起来,每个⽂件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在未来某个时刻可以“还原”。

1、在创建 Git 版本库时,Git 会为我们⾃动创建⼀个唯⼀的 master 分⽀,以及指向 master 的⼀个指 针叫 HEAD。
2、当对⼯作区修改(或新增)的⽂件执⾏ git add 命令时,暂存区⽬录树的⽂件索引会被更新
3、当执⾏提交操纵 git commit 时,master 分⽀会做相应的更新,可以简单明白为暂存区的⽬录 树才会被真正写到版本库中。
通过新建或粘贴进⽬录的⽂件,并不能称之为向堆栈中新增⽂件,⽽只是 在⼯作区新增了⽂件。必须要通过使⽤ git add 和 git commit 命令才能将⽂件添加到堆栈中 进⾏管理。

场景1-添加文件

在包含 .git 的⽬录下新建⼀个 ReadMe ⽂件,可以使⽤ git add 命令可以将⽂件添加到暂存 区:


  • 添加⼀个或多个⽂件到暂存区: git add [file1] [file2] ...
  • 添加当前⽬录下的全部⽂件改动到暂存区: git add .
再使⽤ git commit 命令将暂存区内容添加到本地堆栈中:


  • 提交暂存区全部内容到本地堆栈中: git commit -m "message"
  • 提交暂存区的指定⽂件到堆栈区: git commit [file1] [file2] ... -m "message"
留意 git commit 后⾯的 -m 选项,要跟上描述本次提交的 message,由⽤⼾⾃⼰完成,这部分内 容绝对不能省略,并要好好描述,是⽤来记录提交细节,是给⼈看的。
比方:
  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ vim ReadMe
  2. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ cat ReadMe
  3. hello
  4. hello
  5. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git add ReadMe
  6. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git commit -m "commit my first file"
  7. [master (root-commit) c614289] commit my first file
  8. 1 file changed, 2 insertions(+)
  9. create mode 100644 ReadMe
复制代码
git commit 命令执⾏成功后会告诉我们,1个⽂件被改动(就是我们新添加的ReadMe⽂件),插 ⼊了两⾏内容(ReadMe有两⾏内容)。
还可以多次 add 差别的⽂件,⽽只 commit ⼀次便可以提交全部⽂件,是因为需要提交的⽂件是 通通被 add 到暂存区中,然后⼀次性 commit 暂存区的全部修改。如:
  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ touch file1 file2 file3
  2. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git add file1
  3. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git add file2
  4. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git add file3
  5. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git commit -m "add 3 files"
  6. [master 23807c5] add 3 files
  7. 3 files changed, 0 insertions(+), 0 deletions(-)
  8. create mode 100644 file1
  9. create mode 100644 file2
  10. create mode 100644 file3
复制代码
截⾄⽬前为⽌,已经更够将代码直接提交⾄本地堆栈了。可以使⽤ git log 命令,来检察下历史提交记录:
  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git log
  2. commit ef43bb1d5583e3397fef09f1d174afb835ed8199 (HEAD -> master)
  3. Author: ketil <wangxinhao001124@foxmail.com>
  4. Date:   Tue Oct 1 16:09:35 2024 +0800
  5.     add 3 files
  6. commit 6520e1d571be4e78256481becbb2f9f54b2bb7a4
  7. Author: ketil <wangxinhao001124@foxmail.com>
  8. Date:   Tue Oct 1 15:33:59 2024 +0800
  9.     commit my first file
复制代码
该命令显⽰从最近到最远的提交⽇志,而且可以看到 commit 时的⽇志消息。 如果嫌输出信息太多,看得眼花缭乱的,可以试试加上 --pretty=oneline 参数:
  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git log --pretty=oneline
  2. ef43bb1d5583e3397fef09f1d174afb835ed8199 (HEAD -> master) add 3 files
  3. 6520e1d571be4e78256481becbb2f9f54b2bb7a4 commit my first file
复制代码
需要阐明的是,这些⼀⼤串类似 ef43bb1d...ed8199 的是每次提交的 commit id (版本 号),Git 的 commit id 不是1,2,3……递增的数字,⽽是⼀个 SHA1 计算出来的⼀个⾮常⼤的数 字,⽤⼗六进制表⽰。

检察 .git ⽂件

  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ tree .git/
  2. .git/
  3. ├── branches
  4. ├── COMMIT_EDITMSG
  5. ├── config
  6. ├── description
  7. ├── HEAD
  8. ├── hooks
  9. │   ├── applypatch-msg.sample
  10. │   ├── commit-msg.sample
  11. │   ├── fsmonitor-watchman.sample
  12. │   ├── post-update.sample
  13. │   ├── pre-applypatch.sample
  14. │   ├── pre-commit.sample
  15. │   ├── pre-merge-commit.sample
  16. │   ├── prepare-commit-msg.sample
  17. │   ├── pre-push.sample
  18. │   ├── pre-rebase.sample
  19. │   ├── pre-receive.sample
  20. │   └── update.sample
  21. ├── index
  22. ├── info
  23. │   └── exclude
  24. ├── logs
  25. │   ├── HEAD
  26. │   └── refs
  27. │   └── heads
  28. │   └── master
  29. ├── objects
  30. │   ├── 23
  31. │   │   └── 807c536969cd886c4fb624b997ca575756eed6
  32. │   ├── 83
  33. │   │   └── 0a8c9feefbdc098bbae2cdc25e5034ce1920d7
  34. │   ├── 8f
  35. │   │   └── add50161b6fafa53ce7e79d278dc490240c946
  36. │   ├── 9c
  37. │   │   └── 9e1f0f6bff3015df71a0963004476f5e6cfd54
  38. │   ├── c6
  39. │   │   └── 1428926f3853d4ec6dde904415b0e6c1dabcc6
  40. │   ├── e6
  41. │   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
  42. │   ├── info
  43. │   └── pack
  44. └── refs
  45. ├── heads
  46. │   └── master
  47. └── tags
  48. 18 directories, 27 files
复制代码
1. index 就是我们的暂存区,add 后的内容都是添加到这⾥的。
2. HEAD 就是我们的默认指向 master 分⽀的指针:
  1. ketil@8-134-127-49:~/gitcode$ cat .git/HEAD
  2. ref: refs/heads/master
复制代码
⽽默认的 master 分⽀,其实就是:
  1. ketil@8-134-127-49:~/gitcode$ cat .git/refs/heads/master
  2. 23807c536969cd886c4fb624b997ca575756eed6
复制代码
打印的 23807c536969cd886c4fb624b997ca575756eed6 是什么东西呢?保存的就是当前最新 的 commit id。
3. objects 为 Git 的对象库,⾥⾯包含了创建的各种版本库对象及内容。当执⾏ git add 命令 时,暂存区的⽬录树被更新,同时⼯作区修改(或新增)的⽂件内容被写⼊到对象库中的⼀个新的对象中,就位于".git/objects" ⽬录下,让我们来看看这些对象有何⽤处:
  1. ketil@8-127-134-49:~/gitcode$ ls .git/objects/
  2. 23 83 8f 9c c6 e6 info pack
复制代码
查找 object 时要将 commit id 分成2部分,其前2位是⽂件夹名称,后38位是⽂件名称。 找到这个⽂件之后,⼀般不能直接看到⾥⾯是什么,该类⽂件是颠末 sha (安全哈希算法)加密过的⽂件,好在我们可以使⽤ git cat-file 命令来检察版本库对象的内容:
  1. ketil@8-134-127-49:~/gitcode$ git cat-file -p
  2. 23807c536969cd886c4fb624b997ca575756eed6
  3. tree 830a8c9feefbdc098bbae2cdc25e5034ce1920d7
  4. parent c61428926f3853d4ec6dde904415b0e6c1dabcc6
  5. author hyb91 <wangxinhao001124@foxmail.com> 1683343652 +0800
  6. committer hyb91 <wangxinhao001124@foxmail.com> 1683343652 +0800
  7. add 3 files
  8. # 这就是最近⼀次的提交!
复制代码
此中,还有⼀⾏ tree 830a8c9feefbdc098bbae2cdc25e5034ce1920d7 ,使⽤同样的⽅法,看看结果:
  1. ketil@8-134-127-49:~/gitcode$ git cat-file -p
  2. 830a8c9feefbdc098bbae2cdc25e5034ce1920d7
  3. 100644 blob 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 ReadMe
  4. 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file1
  5. 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file2
  6. 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file3
复制代码
在看 ReadMe 对应的 9c9e1f0f6bff3015df71a0963004476f5e6cfd54 :
  1. ketil@8-134-127-49:~/gitcode$ git cat-file -p
  2. 9c9e1f0f6bff3015df71a0963004476f5e6cfd54
  3. hello
  4. hello
  5. # 这是对ReadMe做的修改!!被git记录了下来!!
复制代码

总结⼀下,在本地的 git 堆栈中,有⼏个⽂件或者⽬录很特殊


  • index: 暂存区, git add 后会更新该内容。
  • HEAD: 默认指向 master 分⽀的⼀个指针。
  • refs/heads/master: ⽂件⾥保存当前 master 分⽀的最新 commit id 。
  • objects: 包含了创建的各种版本库对象及内容,可以简单明白为放了 git 维护的全部修改。


场景二-添加⽂件

们再展⽰⼀种添加⽂件的场景,能加深对⼯作区、暂存区、版本库的明白,⽰比方下:
  1. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ touch file4 #1. 新增file4⽂件
  2. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git add file4 #2. 将file4添加到暂存区
  3. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ touch file5 #3. 新增file5⽂件
  4. ketil@iZ7xvdqducv7olrw8ilvqoZ:~/gitcode$ git commit -m"add file" #4. 提交修改
  5. [master 3d406c0] add file
  6. 1 file changed, 0 insertions(+), 0 deletions(-)
  7. create mode 100644 file4
复制代码
提交后发现打印了 1 file changed, 0 insertions(+), 0 deletions(-) ,意思是只 有⼀个⽂件改变了。git add 是将⽂件添加到暂存区, git commit 是将暂存区的内容添加到本地堆栈 中。由于我们并没有使⽤ git add file5 ,file5 就不在暂存区中维护,所以我们 commit 的时间 其实只是把已经在暂存区的 file4 提交了,⽽遗漏了⼯作区的 file5。怎样提交 file5 呢?很简单,再次 add , commit 即可。

修改⽂件

Git 跟踪并管理的是修改,⽽⾮⽂件。
什么是修改?⽐如新增了⼀⾏,这就是⼀个修改,删除了⼀⾏,也是⼀个修改,更改了某些字符, 也是⼀个修改,删了⼀些⼜加了⼀些,也是⼀个修改,甚⾄创建⼀个新⽂件,也算⼀个修改。
将 ReadMe ⽂件进⾏⼀次修改,此时,堆栈中的 ReadMe 和⼯作区的 ReadMe 是差别的,怎样检察当前堆栈的状态呢? git status 命令⽤于检察在前次提交之后是否有对⽂件进⾏再次修改。
  1. ketil@8.134.127.49:~/gitcode$ git status
  2. On branch master
  3. Changes not staged for commit:
  4. (use "git add <file>..." to update what will be committed)
  5. (use "git restore <file>..." to discard changes in working directory)
  6. modified: ReadMe
  7. no changes added to commit (use "git add" and/or "git commit -a")
复制代码
上⾯的结果显示,ReadMe 被修改过了,但还没有完成添加与提交。
⽬前,只知道⽂件被修改了,如果能知道具体哪些地⽅被修改了,就更好了。
  1. ketil@8.134.127.49:~/gitcode$ git diff ReadMe
  2. diff --git a/ReadMe b/ReadMe
  3. index 9c9e1f0..4a97140 100644
  4. --- a/ReadMe
  5. +++ b/ReadMe
  6. @@ -1,2 +1,3 @@
  7. hello
  8. -hello
  9. +hello
  10. +hello world
复制代码
git diff [file] 命令⽤来显⽰暂存区和⼯作区⽂件的差异,显⽰的格式正是Unix通⽤的diff格 式。也可以使⽤ git diff HEAD -- [file] 命令来检察版本库和⼯作区⽂件的区别。 知道了对 ReadMe 做了什么修改后,再把它提交到本地堆栈就放⼼多了。
  1. ketil@8.134.127.49:~/gitcode$ git add ReadMe
  2. ketil@8.134.127.49:~/gitcode$ git status
  3. On branch master
  4. Changes to be committed:
  5. (use "git restore --staged <file>..." to unstage)
  6. modified: ReadMe
复制代码
git add 之后,就没有看到上⾯ no changes added to commit (use "git add" and/or "git commit -a") 的消息了。接下来继承 git commit 即可:
  1. ketil@8.134.127.49:~/gitcode$ git commit -m "add modify ReadMe file"
  2. [master 94da695] add modify ReadMe file
  3. 1 file changed, 2 insertions(+), 1 deletion(-)
  4. ketil@8.134.127.49:~/gitcode$ git status
  5. On branch master
  6. nothing to commit, working tree clean
复制代码


版本回退

之前也提到过,Git 可以大概管理⽂件的历史版本,这也是版本控制器重要的能⼒。如果有⼀天发现之前的⼯作做的出现了很⼤的题目,需要在某个特定的历史版本重新开始,这个时间,就需要版本 回退的功能了。
执⾏ git reset 命令⽤于回退版本,可以指定退回某⼀次提交的版本。要解释⼀下“回退”本质是 要将版本库中的内容进⾏回退,⼯作区或暂存区是否回退由命令参数决定:
  1. git reset 命令语法格式为: git reset [--soft | --mixed | --hard] [HEAD]
复制代码


  • --mixed 为默认选项,使⽤时可以不⽤带该参数。该参数将暂存区的内容退回为指定提交版本内 容,⼯作区⽂件保持不变。
  • --soft 参数对于⼯作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。
  • --hard 参数将暂存区与⼯作区都退回到指定版本。切记⼯作区有未提交的代码时不要⽤这个命 令,因为⼯作区会回滚,没有提交的代码就再也找不回了,所以使⽤该参数前⼀定要慎重。
  • HEAD 阐明:

    • 可直接写成 commit id,表⽰指定退回的版本
    • HEAD 表⽰当前版本
    • HEAD^ 上⼀个版本
    • HEAD^^ 上上⼀个版本
    • 以此类推...

  • 可以使⽤ 〜数字表⽰:

    • HEAD~0 表⽰当前版本
    • HEAD~1 上⼀个版本
    • HEAD^2 上上⼀个版本
    • 以此类推...

为了便于表述,⽅便测试回退功能,我们先做⼀些准备⼯作:更新3个版本的 ReadMe,并分别进⾏3 次提交,如下所⽰:
  1. # 第⼀次修改提交
  2. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  3. hello
  4. hello
  5. hello world
  6. hello version1
  7. ketil@8-134-127-49:~/gitcode$ git add ReadMe
  8. ketil@8-134-127-49:~/gitcode$ git commit -m"add version1"
  9. [master cff9d1e] add version1
  10. 1 file changed, 1 insertion(+)
  11. # 第⼆次修改提交
  12. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  13. hello
  14. hello
  15. hello world
  16. hello version1
  17. hello version2
  18. ketil@8-134-127-49:~/gitcode$ git add ReadMe
  19. ketil@8-134-127-49:~/gitcode$ git commit -m"add version2"
  20. 1 file changed, 1 insertion(+)
  21. # 第三次修改提交
  22. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  23. hello
  24. hello
  25. hello world
  26. hello version1
  27. hello version2
  28. hello version3
  29. ketil@8-134-127-49:~/gitcode$ git add ReadMe
  30. ketil@8-134-127-49:~/gitcode$ git commit -m"add version3"
  31. [master d95c13f] add version3
  32. 1 file changed, 1 insertion(+)
  33. # 查看历史提交记录
  34. ketil@8-134-127-49:~/gitcode$ git log --pretty=oneline
  35. d95c13ffc878a55a25a3d04e22abfc7d2e3e1383 (HEAD -> master) add version3
  36. 14c12c32464d6ead7159f5c24e786ce450c899dd add version2
  37. cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
  38. ...
复制代码
如今,如果我们在提交完 version3 后, 发现 version 3 编写错误,想回退到 version2,重新基于 version 2 开始编写。由于在这⾥希望的是将⼯作区的内容也回退到 version 2 版本,所以需要⽤到 --hard 参数,⽰比方下:
  1. ketil@8-134-127-49:~/gitcode$ git log --pretty=oneline
  2. d95c13ffc878a55a25a3d04e22abfc7d2e3e1383 (HEAD -> master) add version3
  3. 14c12c32464d6ead7159f5c24e786ce450c899dd add version2
  4. cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
  5. ...
  6. ketil@8-134-127-49:~/gitcode$ git reset --hard
  7. 14c12c32464d6ead7159f5c24e786ce450c899dd
  8. HEAD is now at 14c12c3 add version2
  9. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  10. hello
  11. hello
  12. hello world
  13. hello version1
  14. hello version2
复制代码
我们惊奇的发现,此时 ReadMe ⽂件的内容,已经回退到 version2 了!,当前,我们再次⽤ git log 检察⼀下提交⽇志,发现 HEAD 指向了version2,如下所⽰:
  1. ketil@8-134-127-49:~/gitcode$ git log --pretty=oneline
  2. 14c12c32464d6ead7159f5c24e786ce450c899dd (HEAD -> master) add version2
  3. cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
  4. ...
复制代码
到这⾥⼀般回退功能就演⽰完了,但如今如果我悔恨了,想再回到 version 3 怎么办?可以继承使 ⽤ git reset 命令,回退到 version 3 版本,但我们必须要拿到 version 3 的 commit id 去指定回退的版本。
但看到了 git log 并不能打印出 version 3 的 commit id ,运⽓好的话可以从终端 上去找找之前的记录,运⽓欠好的话 commit id 已经被搞丢了。
Git 还提供了⼀个 git reflog 命令能调停⼀下,该命令⽤来记录本地的每⼀次命令。
  1. ketil@8-134-127-49:~/gitcode$ git reflog
  2. 14c12c3 (HEAD -> master) HEAD@{0}: reset: moving to
  3. 14c12c32464d6ead7159f5c24e786ce450c899dd
  4. d95c13f HEAD@{1}: commit: add version3
  5. 14c12c3 (HEAD -> master) HEAD@{2}: commit: add version2
  6. cff9d1e HEAD@{3}: commit: add version1
  7. 94da695 HEAD@{4}: commit: add modify ReadMe file
  8. 23807c5 HEAD@{5}: commit: add 3 files
  9. c614289 HEAD@{6}: commit (initial): commit my first file
复制代码
如许,就可以很⽅便的找到全部操纵记录了,但 d95c13f 这个是啥东西?这个是 version 3 的 commit id 的部分。没错,Git 版本回退的时间,也可以使⽤部分 commit id 来代表⽬标版 本。
⽰比方下:
  1. # 回退到v3
  2. ketil@8-134-127-49:~/gitcode$ git reset --hard d95c13f
  3. HEAD is now at d95c13f add version3
  4. # 查看⼯作区
  5. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  6. hello
  7. hello
  8. hello world
  9. hello version1
  10. hello version2
  11. hello version3
  12. # 查看log
  13. ketil@8-134-127-49:~/gitcode$ git log --pretty=oneline
  14. d95c13ffc878a55a25a3d04e22abfc7d2e3e1383 (HEAD -> master) add version3
  15. 14c12c32464d6ead7159f5c24e786ce450c899dd add version2
  16. cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
  17. 94da6950d27e623c0368b22f1ffc4bff761b5b00 add modify ReadMe file
  18. 23807c536969cd886c4fb624b997ca575756eed6 add 3 files
  19. c61428926f3853d4ec6dde904415b0e6c1dabcc6 commit my first file
复制代码
Git 的版本回退速度⾮常快,因为 Git 在内部有个指向当前分⽀(此处是master)的 HEAD 指针, refs/heads/master ⽂件⾥保存当前 master 分⽀的最新 commit id 。当我们 在回退版本的时间,Git 仅仅是给 refs/heads/master 中存储⼀个特定的version,可以简单明白 成如下⽰意图:


撤销修改

情况一:对于⼯作区的代码,还没有 add

可以使⽤ git checkout -- [file] 命令让⼯作区的 ⽂件回到最近⼀次 add 或 commit 时的状态。 要留意 git checkout -- [file] 命令中的 -- 很重要,切记不要省略,⼀旦省略,该命令就变为其他意思了。⽰比方下:
  1. # 向ReadMe中新增⼀⾏代码
  2. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  3. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  4. hello
  5. hello git
  6. hello world
  7. hello version1
  8. hello version2
  9. hello version3
  10. This piece of code is like shit #新增代码
  11. # 恢复到上⼀次 add 或 commit
  12. ketil@8-134-127-49:~/gitcode$ git checkout -- ReadMe
  13. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  14. hello
  15. hello git
  16. hello world
  17. hello version1
  18. hello version2
  19. hello version3
复制代码

情况二:已经 add ,但没有 commit

  1. # 向ReadMe中新增⼀⾏代码
  2. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  3. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  4. hello
  5. hello git
  6. hello world
  7. hello version1
  8. hello version2
  9. hello version3
  10. This piece of code is like shit #新增代码
  11. # add 存⼊暂存区
  12. ketil@8-134-127-49:~/gitcode$ git add ReadMe
  13. ketil@8-134-127-49:~/gitcode$ git status
  14. On branch master
  15. Changes to be committed:
  16. (use "git restore --staged <file>..." to unstage)
  17. modified: ReadMe
复制代码
回忆⼀下 git reset 回退命令,该命令如果使⽤ --mixed 参数,可以将暂存区的内容退回为指定的版本内容,但⼯作区⽂件保持不变。那就可以回退下暂存区的内容了。
⽰比方下:
  1. # --mixed 是默认参数,使⽤时可以省略
  2. ketil@8-134-127-49:~/gitcode$ git reset HEAD ReadMe
  3. Unstaged changes after reset:
  4. M ReadMe
复制代码
⽤ git status 检察⼀下,发现如今暂存区是⼲净的,⼯作区有修改。
  1. ketil@8-134-127-49:~/gitcode$ git status
  2. On branch master
  3. Changes not staged for commit:
  4. (use "git add <file>..." to update what will be committed)
  5. (use "git restore <file>..." to discard changes in working directory)
  6. modified: ReadMe
  7. no changes added to commit (use "git add" and/or "git commit -a")
复制代码
还记得怎样抛弃⼯作区的修改吗?
  1. ketil@8-134-127-49:~/gitcode$ git checkout -- ReadMe
  2. ketil@8-134-127-49:~/gitcode$ git status
  3. On branch master
  4. nothing to commit, working tree clean
  5. hyb@139-159-150-152:~/gitcode$ cat ReadMe
  6. hello
  7. hello git
  8. hello world
  9. hello version1
  10. hello version2
  11. hello version3
复制代码
恢复了

情况三:已经 add ,而且也 commit 了

可以 git reset --hard HEAD^ 回退到上⼀个版本。不过,这是有条件的,就是还没有把⾃⼰的本地版本库推送到远程。
  1. # 向ReadMe中新增⼀⾏代码
  2. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  3. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  4. hello
  5. hello git
  6. hello world
  7. hello version1
  8. hello version2
  9. hello version3
  10. This piece of code is like shit #新增代码
  11. # 提交
  12. ketil@8-134-127-49:~/gitcode$ git add ReadMe
  13. ketil@8-134-127-49:~/gitcode$ git commit -m"test quash"
  14. [master 5f71ae1] test quash
  15. 1 file changed, 1 insertion(+)
  16. # 回退
  17. ketil@8-134-127-49:~/gitcode$ git reset --hard HEAD^
  18. HEAD is now at 144a3f8 add file
  19. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  20. hello
  21. hello git
  22. hello world
  23. hello version1
  24. hello version2
  25. hello version3
复制代码


删除文件

在 Git 中,删除也是⼀个修改操纵,如果要删除 file5 ⽂件,怎么做?
  1. ketil@8-134-127-49:~/gitcode$ ls
  2. file1 file2 file3 file4 file5 ReadMe
  3. ketil@8-134-127-49:~/gitcode$ rm file5
复制代码
但如许直接删除是没有⽤的,反⽽徒增烦恼, git status 命令会⽴刻告诉你哪些⽂件被删除了:
  1. ketil@8-134-127-49:~/gitcode$ git status
  2. On branch master
  3. Changes not staged for commit:
  4. (use "git add/rm <file>..." to update what will be committed)
  5. (use "git restore <file>..." to discard changes in working directory)
  6. deleted: file5
  7. no changes added to commit (use "git add" and/or "git commit -a")
复制代码
此时,⼯作区和版本库就不⼀致了,要删⽂件,⽬前除了要删⼯作区的⽂件,还要清除版本库的⽂ 件。
⼀般⾛到这⾥,有两种大概:


  • 确实要从版本库中删除该⽂件
  • 不⼩⼼删错了
对第⼆种情况,很显着误删,需要使⽤ git 来进⾏恢复。
  1. ketil@8-134-127-49:~/gitcode$ git checkout -- file5
  2. ketil@8-134-127-49:~/gitcode$ ls
  3. file1 file2 file3 file4 file5 ReadMe
复制代码
对于第⼀种情况,很显着是没有删完,我们只删除了⼯作区的⽂件。这时就需要使⽤ git rm 将⽂ 件从暂存区和⼯作区中删除,而且 commit :
  1. ketil@8-134-127-49:~/gitcode$ git rm file5
  2. rm 'file5'
  3. ketil@8-134-127-49:~/gitcode$ git status
  4. On branch master
  5. Changes to be committed:
  6. (use "git restore --staged <file>..." to unstage)
  7. deleted: file5
  8. ketil@8-134-127-49:~/gitcode$ git commit -m"deleted file5"
  9. [master 5476bde] deleted file5
  10. 1 file changed, 0 insertions(+), 0 deletions(-)
  11. delete mode 100644 file5
  12. ketil@8-134-127-49:~/gitcode$ git status
  13. On branch master
  14. nothing to commit, working tree clean
复制代码
如今,⽂件就从版本库中被删除了。



二、分支管理

2.1、明白分支

在版本回退⾥,每次提交,Git都把它们串成⼀条时间线,这条时间线就可以明白为是⼀ 个分⽀。截⽌到⽬前,只有⼀条时间线,在Git⾥,这个分⽀叫主分⽀,即 master 分⽀。
再来明白⼀下HEAD,HEAD 严酷来说不是指向提交,⽽是指向master,master才是指向提交的,所 以,HEAD 指向的就是当前分⽀。

 每次提交,master分⽀都会向前移动⼀步,如许,随着不停提交,master分⽀的线也越来越⻓,⽽ HEAD只要⼀直指向master分⽀即可指向当前分⽀。
通过检察当前的版本库,也能清楚的理出思路:
 
  1. ketil@8-134-127-49:~/gitcode$ cat .git/HEAD
  2. ref: refs/heads/masterketil@8-134-127-49:~/gitcode$ cat .git/refs/heads/master5476bdeb12510f7cd72ac4766db7988925ebd302
复制代码


2.2、创建分支

Git ⽀持检察或创建其他分⽀,在这⾥来创建第⼀个⾃⼰的分⽀ dev ,对应的命令为:
  1. ketil@8-134-127-49:~/gitcode$ git branch #查看当前本地所有分⽀
  2. * master
  3. ketil@8-134-127-49:~/gitcode$ git branch dev #新建分⽀dev
  4. ketil@8-134-127-49:~/gitcode$ git branch
  5. dev
  6. * master
复制代码
当创建新的分⽀后,Git 新建了⼀个指针叫 dev, * 表⽰当前 HEAD 指向的分⽀是 master 分⽀。另外,可以通过⽬录结构发现,新的 dev 分⽀:
  1. ketil@8-134-127-49:~/gitcode$ ls .git/refs/heads/
  2. dev master
  3. ketil@8-134-127-49:~/gitcode$ cat .git/refs/heads/*
  4. 5476bdeb12510f7cd72ac4766db7988925ebd302
  5. 5476bdeb12510f7cd72ac4766db7988925ebd302
复制代码
发现⽬前 dev 和 master 指向同⼀个修改。而且也可以验证下 HEAD ⽬前是指向 master 的。
  1. ketil@8-134-127-49:~/gitcode$ cat .git/HEAD
  2. ref: refs/heads/master
复制代码
⼀张图总结:


2.3、切换分支 

那怎样切换到 dev 分⽀下进⾏开发呢?使⽤ git checkout 命令即可完成切换,⽰比方下:
  1. ketil@8-134-127-49:~/gitcode$ git checkout dev
  2. Switched to branch 'dev'
  3. ketil@8-134-127-49:~/gitcode$ git branch
  4. * dev
  5. master
  6. ketil@8-134-127-49:~/gitcode$ cat .git/HEAD
  7. ref: refs/heads/dev
复制代码

 我们发现 HEAD 已经指向了 dev,就表⽰已经成功的切换到了 dev 上!
接下来,在 dev 分⽀下修改 ReadMe ⽂件,新增⼀⾏内容,并进⾏⼀次提交操纵:
  1. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  2. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  3. hello
  4. hello git
  5. hello world
  6. hello version1
  7. hello version2
  8. hello version3
  9. write aaa for new branch
  10. ketil@8-134-127-49:~/gitcode$ git add .
  11. ketil@8-134-127-49:~/gitcode$ git commit -m"modify ReadMe"
  12. [dev 3740dce] modify ReadMe
  13. 1 file changed, 1 insertion(+)
复制代码
如今,dev 分⽀的⼯作完成,可以切换回 master 分⽀:
  1. ketil@8-134-127-49:~/gitcode$ git checkout master
  2. Switched to branch 'master'
  3. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  4. hello
  5. hello git
  6. hello world
  7. hello version1
  8. hello version2
  9. hello version3
复制代码
切换回 master 分⽀后,发现ReadMe⽂件中新增的内容不⻅了?再切回 dev 看看:
  1. ketil@8-134-127-49:~/gitcode$ git checkout dev
  2. Switched to branch 'dev'
  3. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  4. hello
  5. hello git
  6. hello world
  7. hello version1
  8. hello version2
  9. hello version3
  10. write aaa for new branch
复制代码
在 dev 分⽀上,内容还在。为什么会出现这个现象呢?来看看 dev 分⽀和 master 分⽀指向,发 现两者指向的提交是不⼀样的:
  1. ketil@8-134-127-49:~/gitcode$ cat .git/refs/heads/dev
  2. bdaf528ffbb8e05aee34d37685408f0e315e31a4
  3. ketil@8-134-127-49:~/gitcode$ cat .git/refs/heads/master
  4. 5476bdeb12510f7cd72ac4766db7988925ebd302
复制代码
看到这⾥就能明⽩了,因为我们是在dev分⽀上提交的,⽽master分⽀此刻的提交点并没有变,此时 的状态如图如下所⽰。

 当切换到 master 分⽀之时,HEAD 就指向了 master,当然看不到提交了!

2.4、归并分支

为了在 master 主分⽀上能看到新的提交,就需要将 dev 分⽀归并到 master 分⽀,⽰比方下:
  1. ketil@8-134-127-49:~/gitcode$ git branch
  2. * dev
  3. master
  4. ketil@8-134-127-49:~/gitcode$ git checkout master # 切换到 master 上进⾏合并
  5. Switched to branch 'master'
  6. ketil@8-134-127-49:~/gitcode$ git merge dev # 合并 dev 分⽀
  7. Updating 16623e1..3740dce
  8. Fast-forward
  9. ReadMe | 1 +
  10. 1 file changed, 1 insertion(+)
  11. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  12. hello
  13. hello git
  14. hello world
  15. hello version1
  16. hello version2
  17. hello version3
  18. write aaa for new branch
复制代码
git merge 命令⽤于归并指定分⽀到当前分⽀。归并后,master 就能看到 dev 分⽀提交的内容了。此时的状态如下图所示。

Fast-forward 代表“快进模式”,也就是直接把master指向dev的当前提交,所以归并速度⾮常快。 当然,也不是每次归并都能 Fast-forward,会说其他⽅式的归并。


2.5、删除分支

归并完成后, dev 分⽀就没⽤了, 那么dev分⽀就可以被删除掉,留意如果当前正处于某 分⽀下,就不能删除当前分⽀,如:
  1. ketil@8-134-127-49:~/gitcode$ git branch
  2. * dev
  3. master
  4. ketil@8-134-127-49:~/gitcode$ git branch -d dev
  5. error: Cannot delete branch 'dev' checked out at '/home/ketil/gitcode'
复制代码
⽽可以在其他分⽀下删除当前分⽀,如:
  1. ketil@8-134-127-49:~/gitcode$ git checkout master
  2. Switched to branch 'master'
  3. ketil@8-134-127-49:~/gitcode$ git branch -d dev
  4. Deleted branch dev (was bdaf528).
  5. ketil@8-134-127-49:~/gitcode$ git branch
  6. * master
复制代码
此时的状态如图下所示:

 因为创建、归并和删除分⽀⾮常快,所以Git⿎励使⽤分⽀完成某个使命,归并后再删掉分⽀,这和 直接在master分⽀上⼯作效果是⼀样的,但过程更安全。


2.6、归并辩论

可是,在现实分⽀归并的时间,并不是想归并就能归并成功的,偶然候大概会遇到代码辩论的题目。
为了演⽰这题目,创建⼀个新的分⽀ dev1 ,并切换⾄⽬标分⽀,可以使⽤ git checkout - b dev1 ⼀步完成创建并切换的动作,⽰比方下:
  1. ketil@8-134-127-49:~/gitcode$ git checkout -b dev1
  2. Switched to a new branch 'dev1'
  3. ketil@8-134-127-49:~/gitcode$ git branch
  4. * dev1
  5. master
复制代码
在 dev1 分⽀下修改 ReadMe ⽂件,更改⽂件内容如下,并进⾏⼀次提交,如:
  1. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  2. hello
  3. hello git
  4. hello world
  5. hello version1
  6. hello version2
  7. hello version3
  8. write bbb for new branch # 将 aaa 该为 bbb
  9. ketil@8-134-127-49:~/gitcode$ git add .
  10. ketil@8-134-127-49:~/gitcode$ git commit -m"modify ReadMe"
  11. [dev1 0854245] modify ReadMe
  12. 1 file changed, 1 insertion(+), 1 deletion(-)
复制代码
切换⾄ master 分⽀,观察 ReadMe ⽂件内容:
  1. ketil@8-134-127-49:~/gitcode$ git checkout master
  2. Switched to branch 'master'
  3. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  4. hello
  5. hello git
  6. hello world
  7. hello version1
  8. hello version2
  9. hello version3write aaa for new branch
复制代码
发现,切返来之后,⽂件内容由变成了⽼的版本,这种现象很正常,此时在 master 分⽀上,我们对 ReadMe ⽂件再进⾏⼀次修改,并进⾏提交,如下:
  1. ketil@8-134-127-49:~/gitcode$ git branch
  2. dev1
  3. * master
  4. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  5. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  6. hello
  7. hello git
  8. hello world
  9. hello version1
  10. hello version2
  11. hello version3
  12. write ccc for new branch
  13. ketil@8-134-127-49:~/gitcode$ git add .
  14. ketil@8-134-127-49:~/gitcode$ git commit -m"modify ReadMe"
  15. [master c10f6d0] modify ReadMe
  16. 1 file changed, 1 insertion(+), 1 deletion(-)
复制代码
如今,master 和 dev1 分支各自都分别有新的提交,变成如许:

 这种情况下,Git 只能试图把各⾃的修改归并起来,但这种归并就大概会有辩论,如下所⽰:
  1. ketil@8-134-127-49:~/gitcode$ git merge dev1
  2. Auto-merging ReadMe
  3. CONFLICT (content): Merge conflict in ReadMe
  4. Automatic merge failed; fix conflicts and then commit the result.
  5. ketil@8-134-127-49:~/gitcode$ git status
  6. On branch master
  7. You have unmerged paths.
  8. (fix conflicts and run "git commit")
  9. (use "git merge --abort" to abort the merge)
  10. Unmerged paths:
  11. (use "git add <file>..." to mark resolution)
  12. both modified: ReadMe
  13. no changes added to commit (use "git add" and/or "git commit -a")
复制代码
发现 ReadMe ⽂件有辩论后,可以直接检察⽂件内容,要说的是 Git 会⽤ <<<<<<<<<,========, >>>>>> 来标记出差别分⽀的辩论内容,如下所⽰:
  1. hyb@139-159-150-152:~/gitcode$ cat ReadMe
  2. hello
  3. hello git
  4. hello world
  5. hello version1
  6. hello version2
  7. hello version3
  8. <<<<<<< HEAD
  9. write ccc for new branch
  10. =======
  11. write bbb for new branch
  12. >>>>>>> dev1
复制代码
此时必须要⼿动调解辩论代码,并需要再次提交修正后的结果!!(再次提交很重要,切勿忘 记)
  1. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  2. hello bit
  3. hello git
  4. hello world
  5. hello version1
  6. hello version2
  7. hello version3
  8. write bbb for new branch
  9. ketil@8-134-127-49:~/gitcode$ git add .
  10. ketil@8-134-127-49:~/gitcode$ git commit -m"merge ReadMe"
  11. [master 2976afc] merge ReadMe
复制代码
到这⾥辩论就解决完成,此时的状态变成了:

⽤带参数的 git log也可以看到分⽀的归并情况,具体⼤家可以⾃⾏搜索 git log 的⽤法:

  1. ketil@8-134-127-49:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
  2. * 2976afc (HEAD -> master) merge ReadMe
  3. |\
  4. | * c594fd1 (dev1) modify ReadMe
  5. * | c10f6d0 modify ReadMe
  6. |/
复制代码
最后,不要忘记 dev1 分⽀使⽤完毕后就可以删除了:
  1. ketil@8-134-127-49:~/gitcode$ git branch
  2. * master
  3. ketil@8-134-127-49:~/gitcode$ git branch -d dev1
  4. Deleted branch dev1 (was c594fd1).
复制代码


2.7、分支管理战略

通常归并分⽀时,如果大概,Git 会采⽤ Fast forward 模式。还记得如果采⽤ Fast forward 模式之后,形成的归并结果是什么?

 在这种 Fast forward 模式下,删除分⽀后,检察分⽀历史时,会丢掉分⽀信息,看不出来最新提 交到底是 merge 进来的还是正常提交的。
但在归并辩论部分,我们也看到通过解决辩论题目,会再进⾏⼀次新的提交,得到的最终状态为:

 那么这就不是 Fast forward 模式了,如许的好处是,从分⽀历史上就可以看出分⽀信息。比方我 们如今已经删除了在归并辩论部分创建的 dev1 分⽀,但依旧能看到 master 其实是由其他分⽀归并 得到:
  1. ketil@8-134-127-49:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
  2. * 2976afc (HEAD -> master) merge ReadMe
  3. |\
  4. | * c594fd1 modify ReadMe
  5. * | c10f6d0 modify ReadMe
  6. |/
复制代码
Git ⽀持强制禁⽤ Fast forward 模式,那么就会在 merge 时⽣成⼀个新的 commit ,如许, 从分⽀历史上就可以看出分⽀信息。
下⾯实战⼀下 --no-ff ⽅式的 git merge 。⾸先,创建新的分⽀ dev2 ,并切换⾄新的分⽀:
  1. ketil@8-134-127-49:~/gitcode$ git checkout -b dev2
  2. Switched to a new branch 'dev2'
复制代码
修改 ReadMe ⽂件,并提交⼀个新的 commit :
  1. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  2. hello
  3. hello git
  4. hello world
  5. hello version1
  6. hello version2
  7. hello version3
  8. write bbb for new branch
  9. a,b,c,d
  10. ketil@8-134-127-49:~/gitcode$ git add .
  11. ketil@8-134-127-49:~/gitcode$ git commit -m"modify ReadMe"
  12. [dev2 41b082f] modify ReadMe
  13. 1 file changed, 1 insertion(+)
复制代码
切回 master 分⽀,开始归并:
  1. ketil@8-134-127-49:~/gitcode$ git checkout master
  2. Switched to branch 'master'
  3. ketil@8-134-127-49:~/gitcode$ git merge --no-ff -m "merge with no-ff" dev2
  4. Merge made by the 'recursive' strategy.
  5. ReadMe | 1 +
  6. 1 file changed, 1 insertion(+)
  7. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  8. hello
  9. hello git
  10. hello world
  11. hello version1
  12. hello version2
  13. hello version3
  14. write bbb for new branch
  15. a,b,c,d
复制代码
请留意 --no-ff 参数,表⽰禁⽤ Fast forward 模式。禁⽤ Fast forward 模式后归并会创建 ⼀个新的 commit ,所以加上 -m 参数,把描述写进去。
归并后,检察分⽀历史:
  1. ketil@8-134-127-49:~/gitcode$ git log --graph --pretty=oneline --abbrev-commit
  2. * 5bd16b4 (HEAD -> master) merge with no-ff
  3. |\
  4. | * 41b082f (dev2) modify ReadMe
  5. |/
复制代码
可以看到,不使⽤ Fast forward 模式,merge后就像如许:

 所以在归并分⽀时,加上 --no-ff 参数就可以⽤普通模式归并,归并后的历史有分⽀,能看出来曾 经做过归并,⽽ fast forward 归并就看不出来曾经做过归并。


2.8、分支战略

在现实开发中,应该按照⼏个基本原则进⾏分⽀管理:
⾸先,master分⽀应该是⾮常稳定的,也就是仅⽤来发布新版本,寻常不能在上⾯⼲活;
那在哪⼲活呢?⼲活都在dev分⽀上,也就是说,dev分⽀是不稳定的,到某个时间,⽐如1.0版本发布 时,再把dev分⽀归并到master上,在master分⽀发布1.0版本;
每个⼈都在dev分⽀上⼲活,每个⼈都有⾃⼰的分⽀,时不时地往dev分⽀上归并就 可以了。

2.9、bug分支

假如如今正在 dev2 分⽀上进⾏开发,开发到⼀半,突然发现 master 分⽀上⾯有 bug,需要 解决。在Git中,每个 bug 都可以通过⼀个新的暂时分⽀来修复,修复后,归并分⽀,然后将暂时分⽀ 删除。
可如今 dev2 的代码在⼯作区中开发了⼀半,还⽆法提交,怎么办?比方:
  1. ketil@8-134-127-49:~/gitcode$ git branch
  2. * dev2
  3. master
  4. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  5. hello
  6. hello git
  7. hello world
  8. hello version1
  9. hello version2
  10. hello version3
  11. write bbb for new branch
  12. a,b,c,d
  13. i am coding ...
  14. ketil@8-134-127-49:~/gitcode$ git status
  15. On branch dev2
  16. Changes not staged for commit:
  17. (use "git add <file>..." to update what will be committed)
  18. (use "git restore <file>..." to discard changes in working directory)
  19. modified: ReadMe
  20. no changes added to commit (use "git add" and/or "git commit -a")
复制代码
Git 提供了 git stash 命令,可以将当前的⼯作区信息进⾏储藏,被储藏的内容可以在未来某个时间恢复出来。
  1. ketil@8-134-127-49:~/gitcode$ git stash
  2. Saved working directory and index state WIP on dev2: 41b082f modify ReadMe
  3. hyb@139-159-150-152:~/gitcode$ git status
  4. On branch dev2
  5. nothing to commit, working tree clean
复制代码
⽤ git status 检察⼯作区,就是⼲净的(除⾮有没有被 Git 管理的⽂件),因此可以放⼼地创建分 ⽀来修复bug。
储藏 dev2 ⼯作区之后,由于我们要基于master分⽀修复 bug,所以需要切回 master 分⽀,再新 建暂时分⽀来修复 bug,⽰比方下:
  1. ketil@8-134-127-49:~/gitcode$ git checkout master # 切回master
  2. Switched to branch 'master'
  3. ketil@8-134-127-49:~/gitcode$ git checkout -b fix_bug # 新建并切换到 fix_bug 分
  4. Switched to a new branch 'fix_bug'
  5. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  6. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  7. hello  
  8. hello git
  9. hello world
  10. hello version1
  11. hello version2
  12. hello version3
  13. write bbb for new branch
  14. a,b,c,d,e # 修复bug--忘记写e
  15. ketil@8-134-127-49:~/gitcode$ git add ReadMe # 重新add,commit
  16. ketil@8-134-127-49:~/gitcode$ git commit -m"fix bug"
  17. [fix_bug 4bbc0c4] fix bug
  18. 1 file changed, 1 insertion(+), 1 deletion(-)
复制代码
修复完成后,切换到 master 分⽀,并完成归并,最后删除 fix_bug 分⽀:
  1. ketil@8-134-127-49:~/gitcode$ git checkout master
  2. Switched to branch 'master'
  3. ketil@8-134-127-49:~/gitcode$ git merge --no-ff -m"merge fix_bug branch"
  4. fix_bug
  5. Merge made by the 'recursive' strategy.
  6. ReadMe | 2 +-
  7. 1 file changed, 1 insertion(+), 1 deletion(-)
  8. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  9. hello  
  10. hello git
  11. hello world
  12. hello version1
  13. hello version2
  14. hello version3
  15. write bbb for new branch
  16. a,b,c,d,e
  17. ketil@8-134-127-49:~/gitcode$ git branch -d fix_bug
  18. Deleted branch fix_bug (was 4bbc0c4).
复制代码
⾄此,bug 的修复⼯作已经做完了,我们还要继承回到 dev2 分⽀进⾏开发。切换回 dev2 分⽀:
  1. ketil@8-134-127-49:~/gitcode$ git checkout dev2
  2. Switched to branch 'dev2'
  3. ketil@8-134-127-49:~/gitcode$ git status
  4. On branch dev2
  5. nothing to commit, working tree clean
复制代码
⼯作区是⼲净的,刚才的⼯作现场存到哪去了?⽤ git stash list 命令看看:
  1. ketil@8-134-127-49:~/gitcode$ git stash list
  2. stash@{0}: WIP on dev2: 41b082f modify ReadMe
复制代码
⼯作现场还在,Git 把 stash 内容存在某个地⽅了,但是需要恢复⼀下,怎样恢复现场呢?可以使 ⽤ git stash pop 命令,恢复的同时会把 stash 也删了,⽰比方下:
  1. ketil@8-134-127-49:~/gitcode$ git stash pop
  2. On branch dev2
  3. Changes not staged for commit:
  4. (use "git add <file>..." to update what will be committed)
  5. (use "git restore <file>..." to discard changes in working directory)
  6. modified: ReadMe
  7. no changes added to commit (use "git add" and/or "git commit -a")
  8. Dropped refs/stash@{0} (4f873250b3503687b5efd26196776aee7e3724c2)
复制代码
再次检察的时间,我们已经发现已经没有现场可以恢复了
  1. ketil@8-134-127-49:~/gitcode$ git stash list
  2. ketil@8-134-127-49:~/gitcode$
复制代码
另外,恢复现场也可以采⽤ git stash apply 恢复,但是恢复后,stash内容并不删除,需要 ⽤ git stash drop 来删除;
可以多次stash,恢复的时间,先⽤ git stash list 检察,然后恢复指定的stash,⽤命令 git stash apply stash@{0}。
恢复完代码之后我们便可以继承完成开发,开发完成后便可以进⾏提交,比方:
  1. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  2. hello
  3. hello git
  4. hello world
  5. hello version1
  6. hello version2
  7. hello version3
  8. write bbb for new branch
  9. a,b,c,d
  10. i am coding ... Done!
  11. ketil@8-134-127-49:~/gitcode$ git add .
  12. ketil@8-134-127-49:~/gitcode$ git commit -m"modify ReadMe"
  13. [dev2 ed0916d] modify ReadMe
  14. 1 file changed, 1 insertion(+)
复制代码
但留意到了,修复 bug 的内容,并没有在 dev2 上显⽰。此时的状态图为:

 Master 分⽀⽬前最新的提交,是要领先于新建 dev2 时基于的 master 分⽀的提交的,所以 在 dev2 中当然看不⻅修复 bug 的相干代码。
最终⽬的是要让 master 归并 dev2 分⽀的,那么正常情况下切回 master 分⽀直接合 并即可,但如许其实是有⼀定⻛险的。
是因为在归并分⽀时大概会有辩论,⽽代码辩论需要我们⼿动解决(在 master 上解决)。⽆法保证对于辩论题目可以精确地⼀次性解决掉,因为在现实的项⽬中,代码辩论不但⼀两⾏那么简单, 有大概⼏⼗上百⾏,甚⾄更多,解决的过程中不免⼿误堕落,导致错误的代码被归并到 master 上。 此时的状态为:

 解决这个题目的⼀个好的发起就是:最好在⾃⼰的分⽀上归并下 master ,再让 master 去归并 dev ,如许做的⽬的是有辩论可以在本地分⽀解决并进⾏测试,⽽不影响 master 。此时的状态 为:


 对应的实操演⽰如下,要阐明的是,以下演⽰的merge操纵,没有使⽤ --no-ff ,但上述的图⽰是 禁⽤ Fast forward 了模式后得出的,主要是为了⽅便解释题目。
  1. # dev 合并 master
  2. ketil@8-134-127-49:~/gitcode$ git branch
  3. * dev2
  4. master
  5. ketil@8-134-127-49:~/gitcode$ git merge master
  6. Auto-merging ReadMe
  7. CONFLICT (content): Merge conflict in ReadMe
  8. Automatic merge failed; fix conflicts and then commit the result.
  9. # 发⽣冲突
  10. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  11. hello
  12. hello git
  13. hello world
  14. hello version1
  15. hello version2
  16. hello version3
  17. write bbb for new branch
  18. <<<<<<< HEAD
  19. a,b,c,d
  20. i am coding ... Done!
  21. =======
  22. a,b,c,d,e
  23. >>>>>>> master
  24. # 解决冲突并重新提交
  25. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  26. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  27. hello
  28. hello git
  29. hello world
  30. hello version1
  31. hello version2
  32. hello version3
  33. write bbb for new branch
  34. a,b,c,d,e
  35. i am coding ... Done!
  36. ketil@8-134-127-49:~/gitcode$ git add .
  37. ketil@8-134-127-49:~/gitcode$ git commit -m"merge master"
  38. [dev2 447d29f] merge master
  39. ketil@8-134-127-49:~/gitcode$ git status
  40. On branch dev2
  41. nothing to commit, working tree clean
  42. # 切回master
  43. ketil@8-134-127-49:~/gitcode$ git checkout master
  44. Switched to branch 'master'
  45. # master 合并 dev2---⽆需解决冲突!!
  46. ketil@8-134-127-49:~/gitcode$ git merge dev2
  47. Updating 193421f..447d29f
  48. Fast-forward
  49. ReadMe | 1 +
  50. 1 file changed, 1 insertion(+)
  51. ketil@8-134-127-49:~/gitcode$ git status
  52. On branch master
  53. nothing to commit, working tree clean
  54. # 删除 dev2 分⽀
  55. ketil@8-134-127-49:~/gitcode$ git branch -d dev2
  56. Deleted branch dev2 (was 447d29f).
复制代码


2.10、删除暂时分支

软件开发中,总有⽆穷⽆尽的新的功能要不停添加进来。
添加⼀个新功能时,肯定不希望因为⼀些实行性质的代码,把主分⽀搞乱了,所以,每添加⼀个新 功能,最好新建⼀个分⽀,可以将其称之为 feature 分⽀,在上⾯开发,完成后,归并,最后,删除该 feature 分⽀。
可是,如果今天正在某个 feature 分⽀上开发了⼀半,被产品经理突然叫停,说是要停⽌新功 能的开发。虽然⽩⼲了,但是这个 feature 分⽀还是必须当场销毁,留着⽆⽤了。这时使⽤传统 的 git branch -d 命令删除分⽀的⽅法是不⾏的。演⽰如下:
  1. # 新增并切换到 dev3 分⽀
  2. ketil@8-134-127-49:~/gitcode$ git checkout -b dev3
  3. Switched to a new branch 'dev3'
  4. # 开始开发新功能并提交
  5. ketil@8-134-127-49:~/gitcode$ vim ReadMe
  6. ketil@8-134-127-49:~/gitcode$ cat ReadMe
  7. hello
  8. hello git
  9. hello world
  10. hello version1
  11. hello version2
  12. hello version3
  13. write bbb for new branch
  14. a,b,c,d,e
  15. i am coding ... Done!
  16. i am writing new features ...
  17. ketil@8-134-127-49:~/gitcode$ git add .
  18. ketil@8-134-127-49:~/gitcode$ git commit -m"modify ReadMe for new features"
  19. [dev3 cd2f149] modify ReadMe for new features
  20. 1 file changed, 1 insertion(+)
  21. # 此时新功能叫停
  22. # 切回master准备删除dev3
  23. ketil@8-134-127-49:~/gitcode$ git checkout master
  24. Switched to branch 'master'
  25. # 常规删除dev3分⽀时失败
  26. ketil@8-134-127-49:~/gitcode$ git branch -d dev3
  27. error: The branch 'dev3' is not fully merged.
  28. If you are sure you want to delete it, run 'git branch -D dev3'.
复制代码
直接使⽤传统的删除分⽀的⽅法不⾏,按照提⽰,有了如下⽅式:
 
  1. ketil@8-134-127-49:~/gitcode$ git branch -D dev3
  2. Deleted branch dev3 (was cd2f149).
  3. ketil@8-134-127-49:~/gitcode$ git branch
  4. * master
复制代码


小结

分⽀在现实中有什么⽤呢?假设准备开发⼀个新功能,但是需要两周才能完成,第⼀周写了50% 的代码,如果⽴刻提交,由于代码还没写完,不完整的代码库会导致别⼈不能⼲活了。如果等代码全部写完再⼀次提交,⼜存在丢失每天进度的巨⼤⻛险。
如今有了分⽀,就不⽤怕了。创建了⼀个属于⾃⼰的分⽀,别⼈看不到,还继承在原来的分⽀上 正常⼯作,⽽在⾃⼰的分⽀上⼲活,想提交就提交,直到开发完毕后,再⼀次性归并到原来的分⽀ 上,如许,既安全,⼜不影响别⼈⼯作。
而且 Git ⽆论创建、切换和删除分⽀,Git在1秒钟之内就能完成!⽆论版本库是1个⽂件还是1万个⽂件。


三、远程操纵

3.1、明白分布式版本控制系统

⽬前所说的全部内容(⼯作区,暂存区,版本库等等),都是在本地!也就是在笔记本或者计算机上。⽽ Git 其实是分布式版本控制系统。
可以简单明白为,每个⼈的电脑上都是⼀个完整的版本库,如许⼯作的时间,就不需要联⽹了,因为版本库就在⾃⼰的电脑上。既然每个⼈电脑上都有⼀个完整的版本库,那多个⼈怎样协作 呢?⽐⽅说在⾃⼰电脑上改了⽂件A,你的同事也在他的电脑上改了⽂件A,这时,你们俩之间只需把各⾃的修改推送给对⽅,就可以互相看到对方的修改。
分布式版本控制系统的安全性要⾼许多,因为每个⼈电脑⾥都有完整的版本库,某⼀个⼈的电脑坏掉 了不要紧,随便从其他⼈那⾥复制⼀个就可以了。
在现实使⽤分布式版本控制系统的时间,其实很少在两⼈之间的电脑上推送版本库的修改,因为大概 你们俩不在⼀个局域⽹内,两台电脑互相访问不了。也大概今天你的同事病了,他的电脑压根没有开 机。因此,分布式版本控制系统通常也有⼀台充当“中央服务器”的电脑,但这个服务器的作⽤仅仅 是⽤来⽅便“交换”⼤家的修改,没有它⼤家也⼀样⼲活,只是交换修改不⽅便⽽已。有了这个“中央服务器”的电脑,如许就不怕本地出现什么故障了(⽐如运⽓差,硬盘坏了,上⾯的全部东西全部 丢失,包括git的全部内容)。

3.2、远程堆栈

Git 是分布式版本控制系统,同⼀个 Git 堆栈,可以分布到差别的呆板上。怎么分布呢?最早,肯定只有⼀台呆板有⼀个原始版本库,今后,别的呆板可以 “克隆” 这个原始版本库,⽽且每台呆板的版本 库其实都是⼀样的,并没有主次之分。
现实情况每每是如许,找⼀台电脑充当服务器的⻆⾊,每天24⼩时开机,其他每个⼈都从这个“服务 器”堆栈克隆⼀份到⾃⼰的电脑上,而且各⾃把各⾃的提交推送到服务器堆栈⾥,也从服务器堆栈中 拉取别⼈的提交。
完全可以⾃⼰搭建⼀台运⾏ Git 的服务器,不过现阶段,为了学 Git 先搭个服务器绝对是⼩题⼤作。好 在这个世界上有个叫 GitHub 的神奇的⽹站,从名字就可以看出,这个⽹站就是提供 Git 堆栈托管服务的,所以,只要注册⼀个GitHub账号,就可以免费得到 Git 远程堆栈。


3.3、克隆远程堆栈

克隆/下载远端堆栈到本地,需要使⽤ git clone 命令,后⾯跟上远端堆栈的链接,远端堆栈的链接可以从堆栈中找到:选择“克隆/下载”获取远程堆栈链接:
SSH 协议和 HTTPS 协议是 Git 最常使⽤的两种数据传输协议。SSH 协议使⽤了公钥加密和公钥登陆机制,体现了其实⽤性和安全性,使⽤此协议需要将我们的公钥放上服务器,由 Git 服务器进⾏管理。使 ⽤ HTTPS ⽅式时,没有要求,可以直接克隆下来。


  • 使⽤ HTTPS ⽅式:
  1. ketil@8-134-127-49:~$ git clone https://gitee.com/hyb91/git_teaching.git
  2. Cloning into 'git_teaching'...
  3. Username for 'https://gitee.com': hyb91
  4. Password for 'https://hyb91@gitee.com':
  5. remote: Enumerating objects: 4, done.
  6. remote: Counting objects: 100% (4/4), done.
  7. remote: Compressing objects: 100% (4/4), done.
  8. remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
  9. Unpacking objects: 100% (4/4), 1.80 KiB | 1.80 MiB/s, done.
  10. ketil@8-134-127-49:~$ ls
  11. gitcode git_teaching
  12. ketil@8-134-127-49:~$ ls git_teaching/
  13. README.en.md README.md
复制代码


  • 使⽤ SSH ⽅式:
  1. ketil@8-134-127-49:~$ git clone git@gitee.com:hyb91/git_teaching.git
  2. Cloning into 'git_teaching'...
  3. The authenticity of host 'gitee.com (212.64.63.215)' can't be established.
  4. ECDSA key fingerprint is SHA256:FQGC9Kn/eye1W8icdBgrQp+KkGYoFgbVr17bmjey0Wc.
  5. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  6. Warning: Permanently added 'gitee.com,212.64.63.215' (ECDSA) to the list of
  7. known hosts.
  8. git@gitee.com: Permission denied (publickey).
  9. fatal: Could not read from remote repository.
  10. Please make sure you have the correct access rights
  11. and the repository exists.
复制代码
使⽤ SSH ⽅式克隆堆栈,由于没有添加公钥到远端库中,服务器拒绝了 clone 链接。需要设置⼀下:
第⼀步:创建SSH Key。在⽤⼾主⽬录下,看看有没有.ssh⽬录,如果有,再看看这个⽬录下有没有 id_rsa 和 id_rsa.pub 这两个⽂件,如果已经有了,可直接跳到下⼀步。如果没有,需要创建 SSH Key:
  1. # 注意要输⼊⾃⼰的邮箱,然后⼀路回⻋,使⽤默认值即可
  2. ketil@8-134-127-49:~$ ssh-keygen -t rsa -C "wangxinhao001124@foxmail.com"
  3. Generating public/private rsa key pair.
  4. Enter file in which to save the key (/home/hyb/.ssh/id_rsa):
  5. Enter passphrase (empty for no passphrase):
  6. Enter same passphrase again:
  7. Your identification has been saved in /home/hyb/.ssh/id_rsa
  8. Your public key has been saved in /home/hyb/.ssh/id_rsa.pub
  9. The key fingerprint is:
  10. SHA256:sepKZUwKIXjJxYcot49tvOW+Aa+pEhdsRqVDFSmgQZo wangxinhao001124@foxmail.com
  11. The key's randomart image is:
  12. +---[RSA 3072]----+
  13. |*+oB=+           |
  14. |==Oo+ .          |
  15. |E*+o .. .        |
  16. | *o + o          |
  17. | o *o + S        |
  18. |. o ==..         |
  19. | o ..++          |
  20. |. ..+..          |
  21. | ...+o+.         |
  22. +----[SHA256]-----+
复制代码
顺遂的话,可以在⽤⼾主⽬录⾥找到 .ssh ⽬录,⾥⾯有 id_rsa 和 id_rsa.pub 两个⽂件,这两 个就是SSH Key的秘钥对, id_rsa 是私钥,不能泄暴露去, id_rsa.pub 是公钥,可以放⼼地告 诉任何⼈。
  1. ketil@8-134-127-49:~$ ls -a .ssh/
  2. . .. id_rsa id_rsa.pub known_hosts
复制代码
第⼆步:添加⾃⼰的公钥到远端堆栈。
点击 ssh公钥 选项,进⾏设置:

 点击确认后,需要对你进⾏认证,输⼊账号密码即可。
  1. ketil@8-134-127-49:~$ git clone git@gitee.com:hyb91/git_teaching.git
  2. Cloning into 'git_teaching'...
  3. Warning: Permanently added the ECDSA host key for IP address '212.64.63.190'
  4. to the list of known hosts.
  5. remote: Enumerating objects: 4, done.
  6. remote: Counting objects: 100% (4/4), done.
  7. remote: Compressing objects: 100% (4/4), done.
  8. remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
  9. Receiving objects: 100% (4/4), done.
  10. ketil@8-134-127-49:~$ ls
  11. gitcode git_teaching
  12. ketil@8-134-127-49:~$ ls git_teaching/
  13. README.en.md README.md
复制代码
done, 成功。如果有多个⼈协作开发,GitHub/Gitee 答应添加多个公钥,只要把每个⼈的电脑上的 Key 都添加到 GitHub/Gitee,就可以在每台电脑上往 GitHub/Gitee 上提交推送了。
当从远程堆栈克隆后,现实上 Git 会⾃动把本地的 master 分⽀和远程的 master 分⽀对应起来, 而且,远程堆栈的默认名称是 origin 。在本地我们可以使⽤ git remote 命令,来检察远程库的信息,如:
  1. ketil@8-134-127-49:~/git_teaching$ git remote
  2. origin
复制代码
或者,⽤ git remote -v 显⽰更详细的信息:
  1. ketil@8-134-127-49:~/git_teaching$ git remote -v
  2. origin git@gitee.com:hyb91/git_teaching.git (fetch)
  3. origin git@gitee.com:hyb91/git_teaching.git (push)
复制代码
上⾯显⽰了可以抓取和推送的origin的地点。如果没有推送权限,就看不到 push 的地点。推送是什么意思呢?继承往下看。

3.4、向远程堆栈推送

本地已经 clone 成功远程堆栈后,我们便可以向堆栈中提交内容,比方新增⼀个 file.txt ⽂件:
  1. # 新建⽂件
  2. ketil@8-134-127-49:~/git_teaching$ ls
  3. README.en.md README.md
  4. ketil@8-134-127-49:~/git_teaching$ vim file.txt
  5. ketil@8-134-127-49:~/git_teaching$ cat file.txt
  6. hello git
  7. # 提交⽂件
  8. ketil@8-134-127-49:~/git_teaching$ git add .
  9. ketil@8-134-127-49:~/git_teaching$ git commit -m"create file.txt"
  10. [master 7ce3183] create file.txt
  11. 1 file changed, 1 insertion(+)
  12. create mode 100644 file.txt
复制代码
提交时要留意,如果之前设置过全局的 name 和 e-mail,这两项配置需要和 gitee 上配置的⽤⼾名和邮箱⼀致,否则会堕落。或者从来没有设置过全局的 name 和 e-mail,那么第⼀次提交时也 会报错。这就需要重新配置下了,同样要留意需要和 gitee 上配置的⽤⼾名和邮箱⼀致。怎样配置已讲过,在这⾥就不再赘述。
到这⾥已经将内容提交⾄本地堆栈中,怎样将本地堆栈的内容推送⾄远程堆栈呢,需要使⽤ git push 命令,该命令⽤于将本地的分⽀版本上传到远程并归并,命令格式如下:
  1. git push <远程主机名> <本地分⽀名>:<远程分⽀名>
  2. # 如果本地分⽀名与远程分⽀名相同,则可以省略冒号:
  3. git push <远程主机名> <本地分⽀名>
复制代码
此时只要将本地的 master 分⽀推送到 origin 主机的 master 分⽀,则可以:
  1. ketil@8-134-127-49:~/git_teaching$ git push origin master
  2. Enumerating objects: 4, done.
  3. Counting objects: 100% (4/4), done.
  4. Compressing objects: 100% (2/2), done.
  5. Writing objects: 100% (3/3), 308 bytes | 308.00 KiB/s, done.
  6. Total 3 (delta 0), reused 0 (delta 0)
  7. remote: Powered by GITEE.COM [GNK-6.4]
  8. To gitee.com:hyb91/git_teaching.git
  9. c6ce3f0..7ce3183 master -> master
复制代码
推送成功!这⾥由于使⽤的是 SSH 协议,是不⽤每⼀次推送都输⼊密码的,⽅便推送操纵。如果使⽤的是 HTTPS 协议,有个⿇烦地⽅就是每次推送都必须输⼊⼝令。


3.5、拉取远程堆栈

在 gitee 上点击 README.md ⽂件并在线修改它:
此时,远程堆栈是要领先于本地堆栈⼀个版本,为了使本地堆栈保持最新的版本,我们需要拉取下远 端代码,并归并到本地。Git 提供了 git pull 命令,该命令⽤于从远程获取代码并归并本地的版 本。格式如下:
  1. git pull <远程主机名> <远程分⽀名>:<本地分⽀名>
  2. # 如果远程分⽀是与当前分⽀合并,则冒号后⾯的部分可以省略。
  3. git pull <远程主机名> <远程分⽀名>
复制代码
使⽤⼀下:
  1. # 拉取远程分⽀,并与当前分⽀进⾏合并
  2. ketil@8-134-127-49:~/git_teaching$ git pull origin master
  3. remote: Enumerating objects: 5, done.
  4. remote: Counting objects: 100% (5/5), done.
  5. remote: Compressing objects: 100% (3/3), done.
  6. remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
  7. Unpacking objects: 100% (3/3), 1.02 KiB | 1.02 MiB/s, done.
  8. From gitee.com:hyb91/git_teaching
  9. * branch master -> FETCH_HEAD
  10. 7ce3183..60e6b0a master -> origin/master
  11. Updating 7ce3183..60e6b0a
  12. Fast-forward
  13. README.md | 2 ++
  14. 1 file changed, 2 insertions(+)
  15. ketil@8-134-127-49:~/git_teaching$ cat README.md
  16. ...
  17. 第⼀次修改内容
复制代码


3.6、配置Git

忽略特殊⽂件

在⽇常开发中,有些⽂件不想或者不应该提交到远端,⽐如保存了数据库密码的配置⽂件,那怎 么让 Git 知道呢?在 Git ⼯作区的根⽬录下创建⼀个特殊的 .gitignore ⽂件,然后把要忽略的⽂件 名填进去,Git 就会⾃动忽略这些⽂件了。
不需要从头写 .gitignore ⽂件,gitee 在创建堆栈时就可以为我们⽣成,不过需要主动勾选⼀ 下。
如果其时没有选择这个选择,在⼯作区创建⼀个也是可以的。⽆论哪种⽅式,最终都可以得到⼀个完 整的 .gitignore ⽂件,比方想忽略以 .so 和 .ini 末端全部⽂件, .gitignore 的内容 如下:
  1. # 省略选择模本的内容
  2. ...
  3. # My configurations:
  4. *.ini
  5. *.so
复制代码
在 .gitignore ⽂件中也可以指定某个确定的⽂件。
最后⼀步就是把 .gitignore 也提交到远端,就完成了:
  1. ketil@8-134-127-49:~/git_teaching$ vim .gitignore
  2. ketil@8-134-127-49:~/git_teaching$ git add .
  3. ketil@8-134-127-49:~/git_teaching$ git commit -m"add .gitignore"
  4. [master 97811ab] add .gitignore
  5. 1 file changed, 3 insertions(+)
  6. create mode 100644 .gitignore
  7. ketil@8-134-127-49:~/git_teaching$ git push origin master
  8. Enumerating objects: 4, done.
  9. Counting objects: 100% (4/4), done.
  10. Compressing objects: 100% (2/2), done.
  11. Writing objects: 100% (3/3), 362 bytes | 362.00 KiB/s, done.
  12. Total 3 (delta 0), reused 0 (delta 0)
  13. remote: Powered by GITEE.COM [GNK-6.4]
  14. To gitee.com:hyb91/git_teaching.git
  15. 60e6b0a..97811ab master -> master
复制代码
接着就来验证⼀下.gitignore⽂件的能⼒,在⼯作区新增两个⽂件 a.so     b.ini :
  1. ketil@8-134-127-49:~/git_teaching$ touch a.so b.ini
  2. ketil@8-134-127-49:~/git_teaching$ git status
  3. On branch master
  4. Your branch is up to date with 'origin/master'.
  5. nothing to commit, working tree clean
复制代码
查验 .gitignore 的标准就是 git status 命令是不是说 working tree clean 。发现 Git 并没有提⽰在⼯作区中有⽂件新增,果然 .gitignore ⽣效了!  
但有些时间,就是想添加⼀个⽂件到 Git,但由于这个⽂件被 .gitignore 忽略了,根本添加不了,那么可以⽤ -f 强制添加:
  1. $ git add -f [filename]
复制代码
或者发现,大概是 .gitignore 写得有题目,需要找出来到底哪个规则写错了,⽐如说 a.so ⽂件 是要被添加的,可以⽤ git check-ignore 命令检查:
  1. ketil@8-134-127-49:~/git_teaching$ git check-ignore -v a.so
  2. .gitignore:3:*.so     a.so
复制代码
Git 会告诉我们, .gitignore 的第3⾏规则忽略了该⽂件,于是就可以知道应该修订哪个规则。
还有些时间,当编写了规则清除了部分⽂件时,比方:
  1. #  排除所有.开头的隐藏⽂件:
  2. .*
复制代码
但是发现 .* 这个规则把 .gitignore 也清除了。虽然可以⽤ git add -f 强制添加进去,这个时间,可以添加⼀条例外规则:
  1. # 排除所有.开头的隐藏⽂件:
  2. .*
  3. # 不排除.gitignore
  4. !.gitignore
复制代码
把指定⽂件清除在 .gitignore 规则外的写法就是 ! +⽂件名,所以,只需把例外⽂件添加进去即 可。


给命令配置别名

将 git status 简化为 git st ,对应的命令为:
  1. $ git config --global alias.st status
复制代码
--global 参数是全局参数,也就是这些命令在这台电脑的全部Git堆栈下都有⽤。如果不加,那只 针对当前的堆栈起作⽤。
如今敲 git st 看看效果:
  1. ketil@8-134-127-49:~/git_teaching$ git st
  2. On branch master
  3. Your branch is up to date with 'origin/master'.
  4. nothing to commit, working tree clean
复制代码
再来配置⼀个 git last ,让其显⽰最后⼀次提交信息:
  1. $ git config --global alias.last 'log -l'
复制代码
如许,⽤ git last 就能显⽰最近⼀次的提交:
  1. ketil@8-134-127-49:~/git_teaching$ git last
  2. commit 97811abd1d43774aeb54fee32bf4fc76b2b08170 (HEAD -> master,
  3. origin/master, origin/HEAD)
  4. Author: hyb91 <2689241679@qq.com>
  5. Date: Fri May 12 17:27:06 2023 +0800
  6. add .gitignore
复制代码


3.7、标签管理

明白标签

标签 tag ,可以简单的明白为是对某次 commit 的⼀个标识,相当于起了⼀个别名。比方,在项⽬ 发布某个版本的时间,针对最后⼀次 commit 起⼀个 v1.0 如许的标签来标识⾥程碑的意义。
这有什么⽤呢?相较于难以记住的 commit id , tag 很好的解决这个题目,因为 tag ⼀定要给⼀ 个让⼈容易记住,且有意义的名字。当我们需要回退到某个重要版本时,直接使⽤标签就能很快定位 到。
创建标签

在Git中打标签⾮常简单,⾸先,切换到需要打标签的分⽀上
  1. ketil@8-134-127-49:~/git_teaching$ git branch
  2. * master
复制代码
然后,敲命令 git tag [name] 就可以打⼀个新标签:
  1. ketil@8-134-127-49:~/git_teaching$ git tag v1.0
复制代码
可以⽤命令 git tag 检察全部标签:
  1. ketil@8-134-127-49:~/git_teaching$ git tag
  2. v1.0
复制代码
默认标签是打在最新提交的 commit 上的。那怎样在指定的commit上打标签呢?⽅法是找到历史提 交的commit id,然后打上就可以了,⽰比方下:
  1. # 历史记录
  2. ketil@8-134-127-49:~/git_teaching$ git log --pretty=oneline --abbrev-commit
  3. 97811ab (HEAD -> master, tag: v1.0, origin/master, origin/HEAD) add .gitignore
  4. 60e6b0a update README.md.
  5. 7ce3183 create file.txt
  6. c6ce3f0 Initial commit
  7. # 对 Initial commit 这次提交打标签
  8. ketil@8-134-127-49:~/git_teaching$ git tag v0.9 c6ce3f0
  9. ketil@8-134-127-49:~/git_teaching$ git tag
  10. v0.9
  11. v1.0
复制代码
留意,标签不是按时间次序列出,⽽是按字⺟排序的。
可以⽤ git show [tagname] 检察标签信息。
  1. ketil@8-134-127-49:~/git_teaching$ git show v1.0
  2. commit 97811abd1d43774aeb54fee32bf4fc76b2b08170 (HEAD -> master, tag: v1.0,
  3. origin/master, origin/HEAD)
  4. Author: hyb91 <2689241679@qq.com>
  5. Date: Fri May 12 17:27:06 2023 +0800
  6. add .gitignore
  7. diff --git a/.gitignore b/.gitignore
  8. ...
复制代码
Git 还提供可以创建带有阐明的标签,⽤-a指定标签名,-m指定阐明⽂字,格式为:
  1. git tag -a [name] -m "XXX" [commit_id]
复制代码
另外,打完标签之后,使⽤ tree .git 命令检察⼀下本地库有什么变化!

操纵标签

如果标签打错了,也可以删除:
  1. ketil@8-134-127-49:~/git_teaching$ git tagv0.9v1.0ketil@8-134-127-49:~/git_teaching$ git tag -d v0.9Deleted tag 'v0.9' (was c6ce3f0)ketil@8-134-127-49:~/git_teaching$ git tag
  2. v1.0
复制代码
因为创建的标签都只存储在本地,不会⾃动推送到远程。所以,打错的标签可以在本地安全删除。 如果要推送某个标签到远程,使⽤命令 git push origin <tagname>
  1. ketil@8-134-127-49:~/git_teaching$ git tag
  2. v1.0ketil@8-134-127-49:~/git_teaching$ git push origin v1.0Total 0 (delta 0), reused 0 (delta 0)remote: Powered by GITEE.COM [GNK-6.4]To gitee.com:hyb91/git_teaching.git * [new tag] v1.0 -> v1.0
复制代码
此时,检察远端码云,看到了标签已经被更新!
当然,如果本地有许多标签,也可以⼀次性的全部推送到远端:
  1. git push origin --tags
复制代码
如果标签已经推送到远程,要删除远程标签就⿇烦⼀点,先从本地删除:
  1. ketil@8-134-127-49:~/git_teaching$ git tag
  2. v1.0ketil@8-134-127-49:~/git_teaching$ git tag -d v1.0Deleted tag 'v1.0' (was 97811ab)
复制代码
然后,从远程删除。删除命令也是push,但是格式如下:
  1. ketil@8-134-127-49:~/git_teaching$ git push origin :refs/tags/v1.0
  2. remote: Powered by GITEE.COM [GNK-6.4]
  3. To gitee.com:hyb91/git_teaching.git
  4. - [deleted]     v1.0
复制代码
在码云上检察删除成功



四、多人协作

4.1、多⼈协作⼀

⽬前,所完成的⼯作如下:


  • 基本完成 Git 的全部本地库的相干操纵,git基本操纵,分⽀明白,版本回退,辩论解决等等
  • 申请码云账号,将远端信息clone到本地,以及推送和拉取。
之前已经将项⽬ clone 到了指定⽬录,如:
  1. ketil@8-134-127-49:~/git_teaching$ pwd
  2. /home/hyb/git_teaching
复制代码
在 windows 情况下,再 clone 同⼀个项⽬堆栈,来模拟和你⼀起协作开发的另⼀名⼩同伴。
留意,文章中是模拟了两个⽤⼾,现实开发中,每个⽤⼾都有⾃⼰的gitee/github账号,如果要多⼈进 ⾏协同开发,必须要将⽤⼾添加进开发者,⽤⼾才有权限进⾏代码提交。
到此,相当于有了两个⽤⼾,分别在 linux 和 windows 上针对于同项⽬进⾏协作开发,准备⼯作到此结束。
⽬前,堆栈中只有⼀个 master 主分⽀,但在现实的项⽬开发中,在任何情况下其实都是不答应 直接在 master 分⽀上修改代码的,这是为了保证主分⽀的稳定。所以在开发新功能时,常常会新建其他分⽀,供开发时进⾏迭代使⽤。
接下来,就在 gitee 上新建 dev 远程分⽀供使⽤:
创建成功的远程分⽀是可以通过 Git 拉取到本地来,以实现完成本地开发⼯作。
接下来本身和另⼀名开发的⼩同伴都将远程堆栈进⾏⼀次拉取操纵,并观察结果:


  • 对于本身要操纵的是:
  1. ketil@8-134-124-49:~/git_teaching$ git pull
  2. From gitee.com:hyb91/git_teaching
  3. * [new branch] dev -> origin/dev
  4. Already up to date.
  5. # 注:之前讲的 git branch 其实只能查看本地分⽀,要查看远程分⽀需要加上-r选项。
  6. # 但前提是要pull⼀下拉取最新的远端仓库,才能看到最新的内容。
  7. ketil@8-134-127-49:~/git_teaching$ git branch -r
  8. origin/HEAD -> origin/master
  9. origin/dev
  10. origin/master
  11. ketil@8-134-127-49:~/git_teaching$ git checkout -b dev origin/dev
  12. Branch 'dev' set up to track remote branch 'dev' from 'origin'.
  13. Switched to a new branch 'dev'
复制代码
拉取后便可以看到远程的 dev 分⽀,接着切换到 dev 分⽀供本身进⾏本地开发。要阐明的是切换到的是本地的 dev 分⽀,根据⽰例中的操纵,会将本地分⽀和远程分⽀的进⾏关系链接。


  • 对于小同伴要操纵的是:

 如今,就可以一起在 dev 上完成开发。
⾸先,让在 dev 分⽀上进⾏⼀次开发,并 push 到远程。比方:
  1. ketil@8-134-127-49:~/git_teaching$ vim file.txt
  2. ketil@8-134-127-49:~/git_teaching$ cat file.txt
  3. hello git
  4. complete the first function!
  5. ketil@8-134-127-49:~/git_teaching$ git add file.txt
  6. ketil@8-134-127-49:~/git_teaching$ git commit -m "first function"
  7. [dev 305f78a] first function
  8. 1 file changed, 1 deletion(-)
  9. ketil@8-134-127-49:~/git_teaching$ git push origin dev # 将dev分⽀推送到远端
  10. Enumerating objects: 5, done.
  11. Counting objects: 100% (5/5), done.
  12. Compressing objects: 100% (2/2), done.
  13. Writing objects: 100% (3/3), 287 bytes | 287.00 KiB/s, done.
  14. Total 3 (delta 1), reused 0 (delta 0)
  15. remote: Powered by GITEE.COM [GNK-6.4]
  16. To gitee.com:hyb91/git_teaching.git
  17. cc3be59..305f78a dev -> dev
复制代码
⾄此,已经将代码成功推送⾄码云,接下来假如你的⼩同伴要和你协同开发,可巧也要对 file.txt ⽂件作修改,并试图推送。
推送失败,因为你的⼩同伴的最新提交和你推送的提交有辩论,解决办法也很简单,Git已经提⽰ 我们,先⽤ git pull 把最新的提交从 origin/dev 抓下来,然后,在本地进⾏归并,并解决冲 突,再推送。
由此,两名开发者已经开始可以进⾏协同开发了,不停的 git pull/add/commit/push ,遇到了 辩论,就使⽤我们之前讲的辩论处明白决掉辩论。
对于你来说,要想看到⼩同伴的代码,只需要 pull ⼀下即可,比方:
  1. ketil@8-134-127-49:~/git_teaching$ cat file.txt
  2. hello git
  3. complete the first function!
  4. ketil@8-134-127-49:~/git_teaching$ git pull
  5. Updating 305f78a..72c5345
  6. Fast-forward
  7. file.txt | 1 +
  8. 1 file changed, 1 insertion(+)
  9. ketil@8-134-127-49:~/git_teaching$ cat file.txt
  10. hello git
  11. complete the first function!
  12. complete the second function!
复制代码
最后不要忘记,虽然是在分⽀上进⾏多⼈协作开发,但最终的⽬的是要将开发后的代码归并到 master上去,让项⽬运⾏最新的代码。接下来就需要做这件事变了:
  1. # 切换⾄ master分⽀, pull ⼀下,保证本地的master是最新内容。
  2. # 合并前这么做是⼀个好习惯
  3. ketil@8-134-127-49:~/git_teaching$ git checkout master
  4. Switched to branch 'master'
  5. Your branch is up to date with 'origin/master'.
  6. ketil@8-134-127-49:~/git_teaching$ git pull
  7. Already up to date.
  8. # 切换⾄ dev 分⽀, 合并 master 分⽀
  9. # 这么做是因为如果有冲突,可以在dev分⽀上进⾏处理,⽽不是在在master上解决冲突。
  10. # 这么做是⼀个好习惯
  11. ketil@8-134-127-49:~/git_teaching$ git checkout dev
  12. Switched to branch 'dev'
  13. Your branch is up to date with 'origin/dev'.
  14. ketil@8-134-127-49:~/git_teaching$ git merge master
  15. Already up to date.
  16. # 切换⾄ master 分⽀,合并 dev 分⽀
  17. ketil@8-134-127-49:~/git_teaching$ git checkout master
  18. Switched to branch 'master'
  19. Your branch is up to date with 'origin/master'.
  20. ketil@8-134-127-49:~/git_teaching$ git merge dev
  21. Updating 7388a31..72c5345
  22. Fast-forward
  23. file.txt | 2 ++
  24. 1 file changed, 2 insertions(+)
  25. ketil@8-134-127-49:~/git_teaching$ cat file.txt
  26. hello git
  27. complete the first function!
  28. complete the second function!
  29. # 将 master 分⽀推送⾄远端
  30. ketil@8-134-127-49:~/git_teaching$ git status
  31. On branch master
  32. Your branch is ahead of 'origin/master' by 4 commits.
  33. (use "git push" to publish your local commits)
  34. nothing to commit, working tree clean
  35. ketil@8-134-127-49:~/git_teaching$ git push origin master
  36. Total 0 (delta 0), reused 0 (delta 0)
  37. remote: Powered by GITEE.COM [GNK-6.4]
  38. To gitee.com:hyb91/git_teaching.git
  39. 7388a31..72c5345 master -> master
  40. ketil@8-134-127-49:~/git_teaching$ git status
  41. On branch master
  42. Your branch is up to date with 'origin/master'.
  43. nothing to commit, working tree clean
复制代码
此时,检察远端堆栈,master已经是最新代码了。
总结⼀下,在同⼀分⽀下进⾏多⼈协作的⼯作模式通常是如许:


  • ⾸先,可以试图⽤ git push origin branch-name 推送⾃⼰的修改;
  • 如果推送失败,则因为远程分⽀⽐你的本地更新,需要先⽤ git pull 试图归并;
  • 如果归并有辩论,则解决辩论,并在本地提交;
  • 没有辩论或者解决掉辩论后,再⽤git push origin branch-name推送就能成功!
  • 功能开发完毕,将分⽀ merge 进 master,最后删除分⽀。

4.2、多人协作二

⼀般情况下,如果有多需求需要多⼈同时进⾏开发,是不会在⼀个分⽀上进⾏多⼈开发,⽽是⼀个需求或⼀个功能点就要创建⼀个 feature 分⽀。
如今同时有两个需求需要你和你的⼩同伴进⾏开发,那么你们俩便可以各⾃创建⼀个分⽀来完成⾃⼰ 的⼯作。在上个部分我们已经相识了可以从码云上直接创建远程分⽀,其实在本地创建的分⽀也可以 通过推送的⽅式发送到远端。在这个部分我们就来⽤⼀下这种⽅式。
• 对于你来说,可以进⾏以下操纵:
  1. # 新增本地分⽀ feature-1 并切换
  2. ketil@8-134-127-49:~/git_teaching$ git branch
  3. dev
  4. * master
  5. ketil@8-134-127-49:~/git_teaching$ git checkout -b feature-1
  6. Switched to a new branch 'feature-1'
  7. # 新增需求内容-创建function1⽂件
  8. ketil@8-134-127-49:~/git_teaching$ vim function1
  9. ketil@8-134-127-49:~/git_teaching$ cat function1
  10. Done!
  11. # 将 feature-1 分⽀推送到远端
  12. ketil@8-134-127-49:~/git_teaching$ git add function1
  13. ketil@8-134-127-49:~/git_teaching$ git commit -m"add function1"
  14. [feature-1 12ed0db] add function1
  15. 1 file changed, 1 insertion(+)
  16. create mode 100644 function1
  17. ketil@8-134-127-49:~/git_teaching$ git push origin feature-1
  18. Enumerating objects: 4, done.
  19. Counting objects: 100% (4/4), done.
  20. Compressing objects: 100% (2/2), done.
  21. Writing objects: 100% (3/3), 270 bytes | 270.00 KiB/s, done.
  22. Total 3 (delta 1), reused 0 (delta 0)
  23. remote: Powered by GITEE.COM [GNK-6.4]
  24. remote: Create a pull request for 'feature-1' on Gitee by visiting:
  25. remote: https://gitee.com/hyb91/git_teaching/pull/new/hyb91:feature1...hyb91:master
  26. To gitee.com:hyb91/git_teaching.git
  27. * [new branch] feature-1 -> feature-1
复制代码


  • 对于⼩同伴来说,可以进⾏以下操纵:

 此时,在本地,你看不⻅他新建的⽂档,他看不⻅你新建的⽂档。而且推送各⾃的分⽀时,并没有任 何辩论,你俩互不影响。
正常情况下,两人就可以在⾃⼰的分⽀上进⾏专业的开发了!
但你的小同伴告假了,需求还没开发完,需要你帮他继承开发,于是他便把 feature-2 分⽀名告诉你了。这时你就需要在⾃⼰的呆板上切换到 feature-2 分⽀帮助继承开发,要做的操纵如下:
  1. # 必须先拉取远端仓库内容
  2. ketil@8-134-127-49:~/git_teaching$ git pull
  3. ...
  4. From gitee.com:hyb91/git_teaching
  5.     305f78a..72c5345 dev         -> origin/dev
  6.     * [new branch]   feature-2   -> origin/feature-2
  7. ...
  8. # 可以看到远程已经有了feature-2
  9. ketil@8-134-127-49:~/git_teaching$ git branch -a
  10. dev
  11. * feature-1
  12. master
  13. remotes/origin/HEAD -> origin/master
  14. remotes/origin/dev
  15. remotes/origin/feature-1
  16. remotes/origin/feature-2
  17. remotes/origin/master
  18. # 切换到feature-2分⽀上,可以和远程的feature-2分⽀关联起来,
  19. # 否则将来只使⽤ git push 推送内容会失败
  20. ketil@8-134-127-49:~/git_teaching$ git checkout -b feature-2 origin/feature-2
  21. Branch 'feature-2' set up to track remote branch 'feature-2' from 'origin'.
  22. Switched to a new branch 'feature-2'
  23. ketil@8-134-127-49:~/git_teaching$ ls
  24. a.so b.ini file.txt function2 README.en.md README.md
复制代码
切换成功后,便可以看⻅ feature-2 分⽀中的 function2 ⽂件了,接着就可以帮⼩同伴进⾏开发:
  1. # 继续开发
  2. ketil@8-134-127-49:~/git_teaching$ vim function2
  3. ketil@8-134-127-49:~/git_teaching$ cat function2
  4. Done!
  5. Help done!
  6. # 推送内容
  7. ketil@8-134-127-49:~/git_teaching$ git add function2
  8. ketil@8-134-127-49:~/git_teaching$ git commit -m"modify function2"
  9. [feature-2 1079ae7] modify function2
  10. 1 file changed, 2 insertions(+), 1 deletion(-)
  11. ketil@8-134-127-49:~/git_teaching$ git push origin feature-2
  12. Enumerating objects: 5, done.
  13. Counting objects: 100% (5/5), done.
  14. Compressing objects: 100% (2/2), done.
  15. Writing objects: 100% (3/3), 262 bytes | 262.00 KiB/s, done.
  16. Total 3 (delta 1), reused 0 (delta 0)
  17. remote: Powered by GITEE.COM [GNK-6.4]
  18. To gitee.com:hyb91/git_teaching.git
  19. e1233f1..1079ae7 feature-2 -> feature-2
复制代码
检察远程状态,推送成功了。
这时,你的⼩同伴已经修养的差不多,可以继承进⾏⾃⼰的开发⼯作,那么他⾸先要获取到你帮他开 发的内容,然后接着你的代码继承开发。或者你已经帮他开发完了,那他也需要在⾃⼰的电脑上看看 你帮他写的代码。
Pull ⽆效的原因是⼩同伴没有指定本地 feature-2 分⽀与远程 origin/feature-2 分⽀的链接,根据提 ⽰,设置 feature-2 和 origin/feature-2的链接即可:

⽬前,⼩同伴的本地代码和远端保持严酷⼀致。你和你的⼩同伴可以继承在差别的分⽀下进⾏协同开发了。
各⾃功能开发完毕后,不要忘记我们需要将代码归并到master中才算真正意义上的开发完毕。 由于你的⼩同伴率先开发完毕,于是开始 merge :

  • 切换至master,pull一下,保证本地master是最新内容
  1. git chechout master
  2. git pull
复制代码
     2. 切换至 dev 分支,归并 master 分支
  1. git checkout feature-2
  2. git merge master
复制代码
     3. 切换至master分支,归并feature-2 分支
  1. git chechout master
  2. git merge feature-2
复制代码
     4.  将master分支推送至远端
  1. git status
  2. git push origin master
  3. git status
复制代码

当你的⼩同伴将其代码 merge 到 master 后,这是你也开发完成了,也需要进⾏ merge 到 master 操纵,于是你:
  1. # 切换⾄ master分⽀, pull ⼀下,保证本地的master是最新内容。
  2. # 合并前这么做是⼀个好习惯
  3. ketil@8-134-127-49:~/git_teaching$ git checkout master
  4. Switched to branch 'master'
  5. Your branch is up to date with 'origin/master'.
  6. ketil@8-134-127-49:~/git_teaching$ git pull
  7. From gitee.com:hyb91/git_teaching
  8. 72c5345..29006bd master -> origin/master
  9. Updating 72c5345..29006bd
  10. Fast-forward
  11. function2 | 2 ++
  12. 1 file changed, 2 insertions(+)
  13. create mode 100644 function2
  14. # 切换⾄ feature-1 分⽀, 合并 master 分⽀
  15. # 这么做是因为如果有冲突,可以在feature-1分⽀上进⾏处理,⽽不是在在master上解决冲突。
  16. # 这么做是⼀个好习惯
  17. ketil@8-134-127-49:~/git_teaching$ git checkout feature-1
  18. Switched to branch 'feature-1'
  19. Your branch is up to date with 'origin/feature-1'.
  20. ketil@8-134-127-49:~/git_teaching$ git merge master
  21. Merge made by the 'recursive' strategy.
  22. function2 | 2 ++
  23. 1 file changed, 2 insertions(+)
  24. create mode 100644 function2
  25. ketil@8-134-127-49:~/git_teaching$ ls
  26. a.so b.ini file.txt function1 function2 README.en.md README.md
  27. # 1、由于feature-1分⽀已经merge进来了新内容,为了保证远程分⽀最新,所以最好push⼀下。
  28. # 2、要 push 的另⼀个原因是因为在实际的开发中,master的merge操作⼀般不是由我们⾃⼰在本地
  29. 进⾏操作,
  30. # 其他⼈员或某些平台merge时,操作的肯定是远程分⽀,所以就要保证远程分⽀的最新。
  31. # 3、如果 merge 出现冲突,不要忘记需要commit才可以push!!
  32. ketil@8-134-127-49:~/git_teaching$ git status
  33. On branch feature-1
  34. Your branch is ahead of 'origin/feature-1' by 4 commits.
  35. (use "git push" to publish your local commits)
  36. nothing to commit, working tree clean
  37. ketil@8-134-127-49:~/git_teaching$ git push origin feature-1
  38. Enumerating objects: 4, done.
  39. Counting objects: 100% (4/4), done.
  40. Compressing objects: 100% (2/2), done.
  41. Writing objects: 100% (2/2), 299 bytes | 299.00 KiB/s, done.
  42. Total 2 (delta 1), reused 0 (delta 0)
  43. remote: Powered by GITEE.COM [GNK-6.4]
  44. To gitee.com:hyb91/git_teaching.git
  45. ea75a35..4b4c3d4 feature-1 -> feature-1
  46. # 切换⾄ master 分⽀,合并 feature-1 分⽀
  47. ketil@8-134-127-49:~/git_teaching$ git checkout master
  48. Switched to branch 'master'
  49. Your branch is up to date with 'origin/master'.
  50. ketil@8-134-127-49:~/git_teaching$ git merge feature-1
  51. Updating 29006bd..4b4c3d4
  52. Fast-forward
  53. function1 | 1 +
  54. 1 file changed, 1 insertion(+)
  55. create mode 100644 function1
  56. ketil@8-134-127-49:~/git_teaching$ ls
  57. a.so b.ini file.txt function1 function2 README.en.md README.md
  58. # 将 master 分⽀推送⾄远端
  59. ketil@8-134-127-49:~/git_teaching$ git status
  60. On branch master
  61. Your branch is ahead of 'origin/master' by 3 commits.
  62. (use "git push" to publish your local commits)
  63. nothing to commit, working tree clean
  64. ketil@8-134-127-49:~/git_teaching$ git push origin master
  65. Total 0 (delta 0), reused 0 (delta 0)
  66. remote: Powered by GITEE.COM [GNK-6.4]
  67. To gitee.com:hyb91/git_teaching.git
  68. 29006bd..4b4c3d4 master -> master
  69. ketil@8-134-127-49:~/git_teaching$ git status
  70. On branch master
  71. Your branch is up to date with 'origin/master'.
  72. nothing to commit, working tree clean
复制代码
此时, feature-1 和 feature-2 分⽀对于来说就没⽤了, 那么可以直接在远程堆栈中 将dev分⽀删除掉。
 这就是多⼈协作的⼯作模式,⼀旦熟悉了,就⾮常简单。

4.3、远程分⽀删除后,本地 git branch -a 依然能看到的解决办法

当前已经删除了远程的⼏个分⽀,使⽤ git branch -a 命令可以检察全部本地分⽀和远程分⽀,但发现许多在远程堆栈已经删除的分⽀在本地依然可以看到。比方:
  1. ketil@8-134-127-49:~/git_teaching$ git pull
  2. Already up to date.
  3. ketil@8-134-127-49:~/git_teaching$ git branch -a
  4. dev
  5. feature-1
  6. feature-2
  7. * master
  8. remotes/origin/HEAD -> origin/master
  9. remotes/origin/dev
  10. remotes/origin/feature-1
  11. remotes/origin/feature-2
  12. remotes/origin/master
复制代码
 使⽤命令 git remote show origin ,可以检察remote地点,远程分⽀,还有本地分⽀与之相对应关系等信息。
  1. ketil@8-134-127-49:~/git_teaching$ git remote show origin
  2. * remote origin
  3. Fetch URL: git@gitee.com:hyb91/git_teaching.git
  4. Push URL: git@gitee.com:hyb91/git_teaching.git
  5. HEAD branch: master
  6. Remote branches:
  7. master tracked
  8. refs/remotes/origin/dev stale (use 'git remote prune' to remove)
  9. refs/remotes/origin/feature-1 stale (use 'git remote prune' to remove)
  10. refs/remotes/origin/feature-2 stale (use 'git remote prune' to remove)
  11. Local branches configured for 'git pull':
  12. dev merges with remote dev
  13. feature-1 merges with remote feature-1
  14. feature-2 merges with remote feature-2
  15. master merges with remote master
  16. Local ref configured for 'git push':
  17. master pushes to master (up to date)
复制代码
 此时可以看到那些远程堆栈已经不存在的分⽀,根据提⽰,使⽤ git remote prune origin 命令:
  1. ketil@8-134-127-49:~/git_teaching$ git remote prune origin
  2. Pruning origin
  3. URL: git@gitee.com:hyb91/git_teaching.git
  4. * [pruned] origin/dev
  5. * [pruned] origin/feature-1
  6. * [pruned] origin/feature-2
  7. ketil@8-134-127-49:~/git_teaching$ git branch -a
  8. dev
  9. feature-1
  10. feature-2
  11. * master
  12. remotes/origin/HEAD -> origin/master
  13. remotes/origin/master
复制代码
 如许就删除了那些远程堆栈不存在的分⽀。


五、企业开发模式

在传统的 IT 组织下,开发团队(Dev)和运维团队(Ops)之间诉求差别:


  • 开发团队(尤其是敏捷团队)追求变化
  • 运维团队追求稳定
双⽅每每存在利益的辩论。⽐如,精益和敏捷的团队把持续交付作为⽬标,⽽运维团队则为了线上的 稳定⽽强调变更控制。部⻔墙由此建⽴起来,这当然倒霉于 IT 价值的最⼤化。
为了弥合开发和运维之间的鸿沟,需要在⽂化、⼯具和实践⽅⾯的系列变⾰⸺DevOps正式登上舞台。
DevOps(Development和Operations的组合词)是⼀种重视“软件开发⼈员(Dev)”和“IT运维技 术⼈员(Ops)”之间沟通合作的⽂化、运动或惯例。透过⾃动化“软件交付”和“架构变更”的流 程,来使得构建、测试、发布软件可以大概更加地快捷、频繁和可靠。在DevOps的软件开发过程包含计 划、编码、构建、测试、预发布、发布、运维、监控,由此可⻅DevOps的强⼤。
⼀个软件的迭代,在开发⼈员看来,说⽩了就是对代码进⾏迭代,那么就需要对代码进⾏管理。怎样管理的代码呢,那不就是 Git(分布式版本控制系统) !所以 Git 对于开发⼈员来说其重要性就不⾔⽽喻了。

系统开发情况


  • 开发情况:开发情况是程序猿们专⻔⽤于⽇常开发的服务器。为了开发调试⽅便,⼀般打开全部错 误陈诉和测试⼯具,是最底子的情况。
  • 测试情况:⼀个程序在测试情况⼯作不正常,那么肯定不能把它发布到⽣产机上。该情况是开发环 境到⽣产情况的过渡情况。
  • 预发布情况:该情况是为避免因测试情况和线上情况的差异等带来的缺陷漏测⽽设⽴的⼀套情况。 其配置等基本和⽣产情况⼀致,⽬的是能让我们发正式情况时更有把握!所以预发布情况是你的产 品质量最后⼀道防线,因为下⼀步你的项⽬就要上线了。要留意预发布情况服务器不在线上集成服 务器范围之内,为单独的⼀些呆板。
  • ⽣产情况:是指正式提供对外服务的线上情况,比方我们⽬前在移动端或PC端能访问到的APP都是 ⽣产情况。
这⼏个情况也可以说是系统开发的三个重要阶段:开发->测试->上线。⼀张图总结:

 对于规模稍微⼤点的公司来说,可不⽌这么⼏个情况,⽐如项⽬正式上线前还存在仿真/灰度情况,再 ⽐如还存在多套测试情况,以满⾜差别版本上线前测试的需要。
⼀个项⽬的开始从计划开始,⽽⼀个项⽬的成功则从测试开始。⼀套良好的测试体系可以将系统中绝 ⼤部分的致命Bug 解决在系统上线之前。测试系统的美满和成熟也是权衡⼀个软件企业整体⽔平的重 要指标之⼀,测试每每被忽视,因为它对可以的隐性、对软件开发企业不产⽣直接的效益,但是它却 是软件质量的最终保障,乃⾄项⽬可否成功的重要因素!

Git 分支计划规范

情况有了概念后,那么对于开发⼈员来说,⼀般会针对差别的情况来计划分⽀,比方:
分支名称实用情况master主分支生产情况release预发布分支预发布/测试情况develop开发分支开发情况feature告急开发分支本地hotfix告急修复分支本地 注:以上表格中的分⽀和情况的搭配仅是常⽤的⼀种,可视情况⽽定差别的战略。

master 分支



  • master 为主分⽀,该分⽀为只读且唯⼀分⽀。⽤于部署到正式发布情况,⼀般由归并 release 分⽀得到。
  • 主分⽀作为稳定的唯⼀代码库,任何情况下不答应直接在 master 分⽀上修改代码。
  • 产品的功能全部实现后,最终在master分⽀对外发布,另外全部在master分⽀的推送应该打标签 (tag)做记录,⽅便追溯。
  • master 分⽀不可删除。

release 分支



  • release 为预发布分⽀,基于本次上线全部的 feature 分⽀归并到 develop 分⽀之后,基 于 develop 分⽀创建。可以部署到测试或预发布集群。
  • 定名以 release/ 开头,发起的定名规则: release/version_publishtime。
  • release 分⽀主要⽤于提交给测试⼈员进⾏功能测试。发布提测阶段,会以 release 分⽀代码 为基准进⾏提测。
  • 如果在 release 分⽀测试出题目,需要回归验证 develop 分⽀看否存在此题目。
  • release 分⽀属于暂时分⽀,产品上线后可选删除。

develop 分支



  • develop 为开发分⽀,基于master分⽀创建的只读且唯⼀分⽀,始终保持最新完成以及 bug 修 复后的代码。可部署到开发情况对应集群。
  • 可根据需求⼤⼩程度确定是由 feature 分⽀归并,还是直接在上⾯开发(⾮常不发起)。

feature 分支



  • feature 分⽀通常为新功能或新特性开发分⽀,以 develop 分⽀为底子创建 feature 分支
  • 定名以 feature/ 开头,发起的定名规则: feature/user_createtime_feature 。
  • 新特性或新功能开发完成后,开发⼈员需合到 develop 分⽀。
  • ⼀旦该需求发布上线,便将其删除。

hotfix 分支



  • hotfix 分⽀为线上 bug 修复分⽀或叫补丁分⽀,主要⽤于对线上的版本进⾏ bug 修复。当线上 出现告急题目需要⻢上修复时,需要基于 master 分⽀创建 hotfix 分⽀。
  • 定名以 hotfix/ 开头,发起的定名规则: hotfix/user_createtime_hotfix
  • 当题目修复完成后,需要归并到 master 分⽀和 develop 分⽀并推送远程。⼀旦修复上线,便 将其删除。
其实,以上解说的是企业级常⽤的⼀种 Git 分⽀计划规范:Git Flow 模子。但要说的是,该模子并不是适⽤于全部的团队、全部的情况和全部的⽂化。如果你采⽤了持续交付,你会想要⼀些可以大概 尽大概简化交付过程的东西。有些⼈喜欢基于主⼲的开发模式,喜欢使⽤特性标记。然⽽,从测试的⻆度来看,这些反⽽会把他吓⼀跳。
关键在于站在的团队或项⽬的⻆度思索:这种分⽀模子可以帮助你们解决哪些题目?它会带来哪些 题目?这种模式为哪种开发提供更好的⽀持?你们想要⿎励这种⾏为吗?你选择的分⽀模子最终都是为了让⼈们更容易地进⾏软件协作开发。因此,分⽀模子需要考虑到使⽤者的需求,⽽不是盲⽬听信 某些所谓的“成功的分⽀模子”。
所以对于差别公司,规范是会有些许差异,但万变不离其宗,是为了服从与稳定。

企业级项⽬管理实战

DevOps 研发平台
Gitee企业版免费版

修复测试情况 Bug

在 develop 测试出现了Bug,发起⼤家直接在 feature 分⽀上进⾏修复。 修复后的提测上线流程 与 新需求加⼊的流程⼀致。

修改预发布情况 Bug

在 release 测试出现了 Bug,⾸先要回归下 develop 分⽀是否同样存在这个题目。 如果存在,修复流程 与 修复测试情况 Bug流程⼀致。 如果不存在,这种大概性⽐较少,⼤部分是数据兼容题目,情况配置题目等。

修改正式情况 Bug

在 master 测试出现了Bug,⾸先要回归下 release 和 develop 分⽀是否同样存在这个问 题。
如果存在,修复流程 与 修复测试情况 Bug流程⼀致。
如果不存在,这种大概性也⽐较少,⼤部分是数据兼容题目,情况配置题目等。

告急修复正式情况 Bug

需求在测试环节未测试出 Bug,上线运⾏⼀段时间后出现了 Bug,需要告急修复的。
有的企业⾯对告急修复时,⽀持不进⾏测试情况的验证,但还是发起验证下预发布情况。
可基于 master 创建 hotfix/xxx 分⽀,修复完毕后发布到 master 验证,验证完毕后,将 master 代码归并到 develop 分⽀,同时删掉 hotfix/xxx 分⽀。

拓展阅读

其他DevOps研发平台
腾讯coding
阿里云效

 
拓展实践

阿⾥⻜流flow分⽀模子,及项⽬版本管理实践:
https://blog.csdn.net/bbcckkl/article/details/111087267

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

干翻全岛蛙蛙

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表