git基础概念和基础命令

我们来比较一下git的一些命令的区别

  1. reset hard/soft

    1
    2
    $ git reset --hard
    $ git reset --soft
  2. fetch/pull

    1
    2
    $ git fetch
    $ git pull
  3. reset/revert

基本概念图

注意,图中的Stage和Index是同一个东西。

下图中,最后一个diff应该为diff --cached

实验

实验:有关reset

Step 1

本实验说明soft reset不会改变working directory。

  1. 首先我们在空目录执行

    1
    git init
  2. 我们创建a.txt,并且填写其内容为1

  3. 我们执行

    1
    2
    3
    git add .
    git commit -m"a=1"
    git log

    得到输出

    1
    2
    3
    4
    5
    commit 6bd3de7a2b1637dcb686f72af415c5d48f4d5dc2 (HEAD -> master)
    Author: Calvin Neo <calvinneo1995@gmail.com>
    Date: Fri Oct 30 22:46:37 2020 +0800

    a=1
  4. 修改a.txt的内容为2

  5. 执行

    1
    git reset --soft
  6. 查看a.txt的内容为2
    这说明a.txt没有被reset掉

Step 2

本实验说明soft reset不会改变index

  1. 此时,a.txt的内容仍然为2
  2. 执行

    1
    git diff --cached a.txt

    可以看到,a.txt已经被提交到了index里面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    diff --git a/a.txt b/a.txt
    index 56a6051..d8263ee 100644
    --- a/a.txt
    +++ b/a.txt
    @@ -1 +1 @@
    -1
    \ No newline at end of file
    +2
    \ No newline at end of file
  3. 执行

    1
    git reset --soft
  4. 检查a.txt的内容仍然为2

Step 3

本实验说明soft reset能改变Repo

  1. 此时a.txt的内容仍然为2,执行

    1
    git commit -m"a=2"
  2. 检查git log
    可以看到,a=2已经进入了Repo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    commit c0a4d93cb05eb39e149ff50d9b7e54257a51234b (HEAD -> master)
    Author: Calvin Neo <calvinneo1995@gmail.com>
    Date: Fri Oct 30 23:03:53 2020 +0800

    a=2

    commit 6bd3de7a2b1637dcb686f72af415c5d48f4d5dc2
    Author: Calvin Neo <calvinneo1995@gmail.com>
    Date: Fri Oct 30 22:46:37 2020 +0800

    a=1
  3. 执行
    HEAD~1表示HEAD向前一个版本。

    1
    git reset --soft HEAD~1
  4. 检查git log
    发现a=2的提交被回退了

    1
    2
    3
    4
    5
    commit 6bd3de7a2b1637dcb686f72af415c5d48f4d5dc2 (HEAD -> master)
    Author: Calvin Neo <calvinneo1995@gmail.com>
    Date: Fri Oct 30 22:46:37 2020 +0800

    a=1
  5. 检查a.txt
    发现内容还是2,没有变。说明即使回退了Repo,也不会改变工作区。

  6. 执行

    1
    git checkout
  7. 检查a.txt
    发现值内容还是2,这个和图2似乎有矛盾。其实应该要加一个-f

    1
    git checkout -f

实验:有关bisect

Linux内核易于维护的一个原因就是因为Linus要求每一个commit只做一件事,所以他能够通过git bisect快速地二分出错误的提交。

执行下面语句,得到10个提交

1
2
3
4
5
git init
for i in {1..10}
do
echo "print '$i'" > p.py && git add . && git commit -m"p $i"
done

我们的目标是找到第一个打印出大于等于5的错误提交。
我们写一个predicate脚本

1
2
3
4
5
6
7
# test.sh
printed=$(python p.py)
if [ $printed -lt 5 ]; then
exit 0; # good
else
exit 1; # bad
fi

执行下面语句,自动查找到第一个故障提交

1
2
3
4
git bisect start
git status
git bisect bad HEAD
git bisect good HEAD~9

下面执行git bisect run,可以得到以下输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ git bisect run ./test.sh
running ./test.sh
Bisecting: 1 revision left to test after this (roughly 1 step)
[552b511a6d14f48a258338527fb6532a6852d1c2] p 3
running ./test.sh
Bisecting: 0 revisions left to test after this (roughly 0 steps)
[53c92c7bd287ae1cc06a0ff1eeb57f6bb9525424] p 4
running ./test.sh
6254d17800fc63757fd6b478e80db23480aec6f7 is the first bad commit
commit 6254d17800fc63757fd6b478e80db23480aec6f7
Author: Calvin Neo <calvinneo1995@gmail.com>
Date: Mon Nov 9 22:56:36 2020 +0800

p 5

:100644 100644 06cfe93d366cdbd541402affbcbf2305c1d7409b a6b723841de0d34ba0a7d30e7ba3b16ff48ad8e4 M p.py
bisect run success