斐波那契数列为例的 git 实战

本文创设一个情景:斐波那契数列求法的实现,来演练 git 和 github 的使用。斐波那契数列的介绍参见 [2],其不同时空复杂度的实现见 [3]。

步骤一:在 github 上建立一个远程仓库

github 现在要勾选好多东西才能创建仓库了。这些勾勾,勾了之后就会生成 .gitgnore,README.md。建立好远程仓库,github 会自动跳转到仓库页面。绿绿的 Code 按钮点开能看到仓库地址。接下来把仓库 clone 到本地。

对 c/c++ 项目来说,Windows 下用命令行工具的话,首选 VS Developer Command Prompt。此工具会设置好 c/c++ 编译链接需要的路径。从这玩意打开 VSCode (这也是 VSCode Doc 里面推荐的做法,见 [4]),创建 task.json 的时候会自动设置好,很爽。如果你想像我一样作死看看直接用 cmd 需要配置多少编译和链接路径,劝你放弃。

**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.7.4
** Copyright (c) 2020 Microsoft Corporation
**********************************************************************

D:Projects>git clone https://github.com/tandandanw/fibonacci.git
Cloning into 'fibonacci'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), 941 bytes | 4.00 KiB/s, done.

D:Projects>cd fibonacci

D:Projectsfibonacci>code .

D:Projectsfibonacci>git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

在 github 仓库页面 Insights >> Network,可以看到 Network graph,显示仓库的 commits timeline。

步骤二:修改 master 主分支

在 VSCode 中打开项目之后,新建一个 fibo.c 文件,键入基本的框架代码:只包含计算斐波那契数列的函数和主函数。

#include <stdio.h>

int fibonacci(int n)
{
    return -1;
}

int main(int args, char *argv[])
{
    int n; scanf("%d", &n);
    int result = fibonacci(n);
    printf("%d", result);

    return 0;
}

这时候再看看 status 就会发现此文件已经变成了 Untracked files 的一员。再执行 add 命令,fibo.c 就暂存到了 Index 区。

D:Projectsfibonacci>git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        fibo.c

nothing added to commit but untracked files present (use "git add" to track)

D:Projectsfibonacci>git add fibo.c

D:Projectsfibonacci>git status
On branch master
Your branch is up to date with 'origin/master'.    

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   fibo.c

如果要把 fibo.c 从 Index 里移除,使用 reset 命令。只有 Index 中的文件才会在提交代码时存入版本库。

D:Projectsfibonacci>git reset HEAD fibo.c

D:Projectsfibonacci>git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        fibo.c

nothing added to commit but untracked files present (use "git add" to track)

为了确保代码运行正确,先编译一下。 因为现在只有一个文件,所以直接在当前目录下编译生成 .exe文件。如果 setting.json 里面没有给终端设置一下七七八八的参数的话,直接在 VSCode 的菜单里 Terminal >> Configure Default Build Task 一路回车就可以生成默认的 tasks.json。然后把鼠标切回 fibo.c ,按下 Ctrl + Shift + B 就可以编译了。结果如下:

> Executing task: cl.exe /Zi /EHsc /Fe: d:Projectsfibonaccifibo.exe d:Projectsfibonaccifibo.c <

Microsoft (R) C/C++ Optimizing Compiler Version 19.27.29111 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

fibo.c
Microsoft (R) Incremental Linker Version 14.27.29111.0    
Copyright (C) Microsoft Corporation.  All rights reserved.

/debug
/out:d:Projectsfibonaccifibo.exe
fibo.obj

Terminal will be reused by tasks, press any key to close it.

运行一下 fibo.exe,不出意外的话无论输入什么结果都是 -1。

D:Projectsfibonacci>fibo.exe
1
-1
D:Projectsfibonacci>fibo.exe
5
-1
D:Projectsfibonacci>fibo.exe
100000
-1

现在我们用 dir 和 status 观察一下当前的文件。

D:Projectsfibonacci>dir
 Volume in drive D is Working Disk
 Volume Serial Number is 584C-873F

 Directory of D:Projectsfibonacci

2020/10/01  22:23    <DIR>          .
2020/10/01  22:23    <DIR>          ..
2020/10/01  16:46               482 .gitignore     
2020/10/01  22:17    <DIR>          .vscode        
2020/10/01  22:26               445 fibo.c
2020/10/01  22:23           494,080 fibo.exe       
2020/10/01  22:23         2,045,228 fibo.ilk       
2020/10/01  22:23             5,907 fibo.obj       
2020/10/01  22:23         9,605,120 fibo.pdb       
2020/10/01  16:46                52 README.md      
2020/10/01  22:23            77,824 vc140.pdb      
               8 File(s)     12,229,138 bytes      
               3 Dir(s)  483,415,437,312 bytes free

D:Projectsfibonacci>git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .vscode/
        fibo.c

nothing added to commit but untracked files present (use "git add" to track)

为什么 Untracked files 里面没有出现编译的中间文件 .obj 之流呢?因为 .gitgnore 里设置了啥文件不加入版本控制。一般来说版本控制里不应当加入的是可以用已有文件生成的文件(体会一下)。是时候了,现在第一个版本已经好了,用 commit 命令提交新版本。提交后用 log 命令可以看到当前版本前所有的版本提交信息。可以看到,我们本地的 master 分支已经比远程 origin 的 master 前进了一个版本。如果想要回退到前一个版本,可以使用 reset —hard HEAD^。回退命令的 --hard 参数后面可以有很多种表示方式,详情键入 git help reset 查阅。此时想要查看“未来”的版本需要使用 reflog 命令。

D:Projectsfibonacci>git commit -m "Create empty framework" 
[master fa3dafe] Create empty framework
 1 file changed, 20 insertions(+)      
 create mode 100644 fibo.c

D:Projectsfibonacci>git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .vscode/

nothing added to commit but untracked files present (use "git add" to track)

D:Projectsfibonacci>git log
commit fa3dafe3618c5fc874b8bdf1f844a0b0d85c0f7a (HEAD -> master)
Author: tandandanw <tandandanw@gmail.com>
Date:   Thu Oct 1 22:38:46 2020 +0800

    Create empty framework

commit 8cc6340840c711802141ce26c4a47f3dfad7ee76 (origin/master, origin/HEAD)
Author: tandandan <passerbytandd@gmail.com>
Date:   Thu Oct 1 16:32:18 2020 +0800

    Initial commit

D:Projectsfibonacci>git reset --hard HEAD^^
HEAD is now at 8cc6340 Initial commit

D:Projectsfibonacci>git log
commit 8cc6340840c711802141ce26c4a47f3dfad7ee76 (HEAD -> master, origin/master, origin/HEAD)
Author: tandandan <passerbytandd@gmail.com>
Date:   Thu Oct 1 16:32:18 2020 +0800

    Initial commit

D:Projectsfibonacci>git reflog
8cc6340 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: reset: moving to HEAD^
fa3dafe HEAD@{1}: reset: moving to HEAD
fa3dafe HEAD@{2}: commit: Create empty framework
8cc6340 (HEAD -> master, origin/master, origin/HEAD) HEAD@{3}: clone: from https://github.com/tandandanw/fibonacci.git

D:Projectsfibonacci>git reset --hard fa3d
HEAD is now at fa3dafe Create empty framework

(此处出现了一个问题,键入 HEAD^ 的时候这个 VS Prompt 问我 More? 查了一下是因为 cmd 中换行符默认是 ^ 而不是 ,所以它愚蠢地以为还有下一行。解决方案见 [5])

步骤三:增加一个分支

增加分支之前,我又给 master 增加了几个版本。每个版本增加的功能都应该干净、简单。而且要在对应的 commit log message 里面描述清楚。目前的版本树如下:

commit bb9e88a77c054b4d48991109ffceb8ad21b0fc46 (HEAD -> master)
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 10:38:35 2020 +0800

    Add assert for safety

commit 4d557ffde86633cba27051d5646d8c1948457496
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 10:34:25 2020 +0800

    Add timer and multi-times calculation

commit b29bc4d0edf17f3a1c745e141b7670ca543fe4f4
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 10:22:02 2020 +0800

    Redirect stdin to file input

commit 9821de541f3f6da4faac33be803b7ea2610f4c83
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 10:19:10 2020 +0800

    Add single argument implementation

commit a5a5ea39bd21d01f8ca5d5a1ecd9732824f5e51e
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 10:10:08 2020 +0800

    Filter vscode config files

commit fa3dafe3618c5fc874b8bdf1f844a0b0d85c0f7a
Author: tandandanw <tandandanw@gmail.com>
Date:   Thu Oct 1 22:38:46 2020 +0800

    Create empty framework

commit 8cc6340840c711802141ce26c4a47f3dfad7ee76 (origin/master, origin/HEAD)
Author: tandandan <passerbytandd@gmail.com>
Date:   Thu Oct 1 16:32:18 2020 +0800

    Initial commit

接下来为了创建分支,先回退到最开始的版本。然后使用 checkout 命令创建新分支。

D:Projectsfibonacci>git reset --hard fa3d
HEAD is now at fa3dafe Create empty framework

D:Projectsfibonacci>git checkout -b tddbranch
Switched to a new branch 'tddbranch'

D:Projectsfibonacci>git branch
  master
* tddbranch

现在可以在新建分支里继续和 master 不一样的版本更新了。我又加了几个版本之后,log 如下:

commit 170ae6bfd7816f63e17e32573b8a8d74c8575847 (HEAD -> tddbranch)
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:07:51 2020 +0800

    Add assert

commit 5d5d8e81a578834e3c52a2934be8c6bc11e36766
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:06:29 2020 +0800

    Add timer and times

commit d7afacfaaa95b454f564bc07f140a266eb36a358
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:04:43 2020 +0800

    Redirect stdin to file

commit 814bb007c24055996a4bc82b369de13455527563
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:01:41 2020 +0800

    Add binet formula implementation

commit fa3dafe3618c5fc874b8bdf1f844a0b0d85c0f7a (master)
Author: tandandanw <tandandanw@gmail.com>
Date:   Thu Oct 1 22:38:46 2020 +0800

    Create empty framework

commit 8cc6340840c711802141ce26c4a47f3dfad7ee76 (origin/master, origin/HEAD)
Author: tandandan <passerbytandd@gmail.com>
Date:   Thu Oct 1 16:32:18 2020 +0800

    Initial commit

然后可以用 rebase 命令来整理一下提交记录。指定 -i 会在命令行打开一个 vi 的文本编辑器编辑提交记录。

D:Projectsfibonacci>git rebase -i "HEAD^^^"

pick d7afacf Redirect stdin to file
pick 5d5d8e8 Add timer and times
pick 170ae6b Add assert

# Rebase 814bb00..170ae6b onto 814bb00 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
~   

这时如果把第二行删掉,保存之后,当前的 HEAD 会变成第一行的版本,即将写入的版本是第三行。cmd 显示如下:

"D:/Projects/fibonacci/.git/rebase-merge/git-rebase-todo" [converted][unix] 27L, 1152C written
error: could not apply 170ae6b... Add assert
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 170ae6b... Add assert
Auto-merging fibo.c
CONFLICT (content): Merge conflict in fibo.c

在 VSCode 里可以对冲突的地方进行修改,或直接编辑文件。完成修改后用 add 冲突文件到 Index,再用 rebase -- continue 命令完成操作。再看 log 发现已经消失了一个版本。

D:Projectsfibonacci>git add fibo.c

D:Projectsfibonacci>git rebase --continue

Add assert

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto 814bb00
# Last commands done (2 commands done):
#    pick d7afacf Redirect stdin to file
#    pick 170ae6b Add assert
# No commands remaining.
# You are currently rebasing branch 'tddbranch' on '814bb00'.
#
# Changes to be committed:
#       modified:   fibo.c
#
# Untracked files:
#       .vscode/
#
~

"D:/Projects/fibonacci/.git/COMMIT_EDITMSG" [converted][unix] 18L, 477C written

[detached HEAD 7da34b8] Add assert
 1 file changed, 24 insertions(+), 8 deletions(-)
Successfully rebased and updated refs/heads/tddbranch.

D:Projectsfibonacci>git log
commit 7da34b84207bbc75a9ad2bd2f952123ea25267fa (HEAD -> tddbranch)
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:07:51 2020 +0800

    Add assert

commit d7afacfaaa95b454f564bc07f140a266eb36a358
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:04:43 2020 +0800

    Redirect stdin to file

commit 814bb007c24055996a4bc82b369de13455527563
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:01:41 2020 +0800

    Add binet formula implementation

commit fa3dafe3618c5fc874b8bdf1f844a0b0d85c0f7a (master)
Author: tandandanw <tandandanw@gmail.com>
Date:   Thu Oct 1 22:38:46 2020 +0800

    Create empty framework

commit 8cc6340840c711802141ce26c4a47f3dfad7ee76 (origin/master, origin/HEAD)
Author: tandandan <passerbytandd@gmail.com>
Date:   Thu Oct 1 16:32:18 2020 +0800

    Initial commit                                                                                                                    

步骤四:合并

进行合并操作之前,切到 master 分支,先 pull 同步远程仓库,再 merge。这里使用 --no--ff 关闭快进合并(fast-farward merge)防止分支被覆盖。编辑解决冲突之后,push 到远程仓库中。


D:Projectsfibonacci>git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

D:Projectsfibonacci>git pull
Already up to date.

D:Projectsfibonacci>git merge --no-ff tddbranch
Merge made by the 'recursive' strategy.
 data.txt |  6 ++++++
 fibo.c   | 47 ++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 44 insertions(+), 9 deletions(-)
 create mode 100644 data.txt

D:Projectsfibonacci>git log
commit cd6adc784d38ac56ab2c7a2c51d13f63c58737fe (HEAD -> master)
Merge: fa3dafe 7da34b8
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 12:35:12 2020 +0800

    Merge branch 'tddbranch'

commit 7da34b84207bbc75a9ad2bd2f952123ea25267fa (tddbranch)
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:07:51 2020 +0800

    Add assert

commit d7afacfaaa95b454f564bc07f140a266eb36a358
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:04:43 2020 +0800

    Redirect stdin to file

commit 814bb007c24055996a4bc82b369de13455527563
Author: tandandanw <tandandanw@gmail.com>
Date:   Sat Oct 3 11:01:41 2020 +0800

    Add binet formula implementation

commit fa3dafe3618c5fc874b8bdf1f844a0b0d85c0f7a
Author: tandandanw <tandandanw@gmail.com>
Date:   Thu Oct 1 22:38:46 2020 +0800

    Create empty framework

commit 8cc6340840c711802141ce26c4a47f3dfad7ee76 (origin/master, origin/HEAD)
Author: tandandan <passerbytandd@gmail.com>
Date:   Thu Oct 1 16:32:18 2020 +0800

    Initial commit

D:Projectsfibonacci>git status
On branch master
Your branch is ahead of 'origin/master' by 5 commits.
  (use "git push" to publish your local commits)

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        .vscode/

nothing added to commit but untracked files present (use "git add" to track)

D:Projectsfibonacci>git push
Enumerating objects: 15, done.
Counting objects: 100% (15/15), done.
Delta compression using up to 8 threads
Compressing objects: 100% (13/13), done.
Writing objects: 100% (14/14), 1.98 KiB | 1011.00 KiB/s, done.
Total 14 (delta 7), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (7/7), done.
To https://github.com/tandandanw/fibonacci.git
   8cc6340..cd6adc7  master -> master

此时本地的 reflog 输出如下(试错操作很多问题T.T):

D:Projectsfibonacci>git reflog
cd6adc7 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: reset: moving to cd6a
9473fac HEAD@{1}: reset: moving to 9473
cd6adc7 (HEAD -> master, origin/master, origin/HEAD) HEAD@{2}: reset: moving to cd6a
4d557ff HEAD@{3}: reset: moving to 4d55
bb9e88a HEAD@{4}: reset: moving to bb9e
fa3dafe HEAD@{5}: rebase (finish): returning to refs/heads/master
fa3dafe HEAD@{6}: rebase (start): checkout HEAD^^
9473fac HEAD@{7}: rebase (finish): returning to refs/heads/master
9473fac HEAD@{8}: rebase (start): checkout HEAD^
9473fac HEAD@{9}: reset: moving to HEAD
9473fac HEAD@{10}: commit: After merge
fa3dafe HEAD@{11}: reset: moving to fa3d
cd6adc7 (HEAD -> master, origin/master, origin/HEAD) HEAD@{12}: merge tddbranch: Merge made by the 'recursive' strategy.
fa3dafe HEAD@{13}: checkout: moving from tddbranch to master
7da34b8 (tddbranch) HEAD@{14}: rebase (continue) (finish): returning to refs/heads/tddbranch
7da34b8 (tddbranch) HEAD@{15}: rebase (continue): Add assert
d7afacf HEAD@{16}: rebase (start): checkout HEAD^^^
170ae6b HEAD@{17}: commit: Add assert
5d5d8e8 HEAD@{18}: commit: Add timer and times
d7afacf HEAD@{19}: commit: Redirect stdin to file
814bb00 HEAD@{20}: commit: Add binet formula implementation
fa3dafe HEAD@{21}: checkout: moving from master to tddbranch
fa3dafe HEAD@{22}: reset: moving to fa3d
bb9e88a HEAD@{23}: commit: Add assert for safety
4d557ff HEAD@{24}: commit: Add timer and multi-times calculation
b29bc4d HEAD@{25}: commit: Redirect stdin to file input
9821de5 HEAD@{26}: commit: Add single argument implementation
a5a5ea3 HEAD@{27}: commit: Filter vscode config files
fa3dafe HEAD@{28}: reset: moving to fa3d
8cc6340 HEAD@{29}: reset: moving to HEAD^
fa3dafe HEAD@{30}: reset: moving to HEAD
fa3dafe HEAD@{31}: commit: Create empty framework
8cc6340 HEAD@{32}: clone: from https://github.com/tandandanw/fibonacci.git

时间线如下图。可以看到,非快进式 merge 了分支里的代码到 master 里。我之前在本地 master 里增加的版本,因为没有 push,所以在本地能够查看,在远程不能。

步骤五:等待别人的 fork 然后处理 request



其他

搜索分支命名规范的时候,找到了 [6],可以一看。实际应用中应该各有各的规范,到时再学习就好。工具类的东西,即用即学。

项目地址在

本篇博客写在电脑键盘部分损毁时,费时费力。还是熟悉了一下之前确实没怎么用过的命令。

参考

[1] https://mp.weixin.qq.com/s/Km5KuXPETvG0wCGHrvj9Vg
[2] https://zh.wikipedia.org/wiki/斐波那契数列
[3] https://leetcode-cn.com/problems/fibonacci-number/solution/
[4] https://code.visualstudio.com/docs/cpp/config-msvc
[5] https://blog.csdn.net/qq_32623363/article/details/78968077
[6] https://juejin.im/post/6844903635533594632

原文地址:https://www.cnblogs.com/tandandan/p/13758241.html