本文创设一个情景:斐波那契数列求法的实现,来演练 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