假设 A 创建一个 git 版本仓库,将仓库的访问地址告诉 B,B 就可以“克隆(clone)”这个版本仓库到自己的电脑中(当然前提是网络连通且具有相应的权限),而且这两个仓库可以随时同步各自的修改变化。
那么如果有很多人呢?通常我们会设置一台电脑作为公共仓库服务器,一个团队成员(通常是负责管理版本的人)创建(init)好仓库然后“推送(push)”到公共仓库服务器上,这个服务器上的仓库就成为团队共享的仓库(team repo),其他人就可以克隆 team repo 到自己的电脑,team repo 成为是所有人公共的“源(origin)”。
如此这般之后,所有人都可以在自己电脑上工作,在自己的本地仓库中建立新的版本,并在需要时把本地仓库中的版本 推送(push) 到 team repo,也可以从 team repo 抓取(pull) 其他人提交的版本到自己的本地仓库。如果这个过程中产生了冲突(conflict),比如两个人提交的两个版本中有对同一个文件的不相容的修改,有多种选项来进行解决。
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
nothing added to commit but untracked files present (use "git add" to track)
from datetime import datetime
print(datetime.now().strftime('今天是%Y年%m月%d日'))
[x] 同时我们也可以改一下之前有的 README.md 文件,随便改点什么都可以,然后回到命令行界面运行 git status 可以看到类似下面的信息:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
hello.py
today.py
no changes added to commit (use "git add" and/or "git commit -a")
[x] 第一段 Changes not staged for commit: 列出的是已经加入版本仓库但有了新变化的文件(README.md),如果我们发现改动是误操作,希望恢复到该文件上一个 commit 的状态可以使用这个命令:git restore README.md;或者旧版本的命令 git checkout -- README.md。
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: README.md
new file: hello.py
new file: today.py
[x] 我们可以看到有三个文件,两个新的,一个修改的,放在 staging area 等待提交。这个时候我们考虑到 README.md 的修改和添加的两个新文件是两件事,最好分开提交,所以我们想先把第一项从 staging area 移出来,这时候就用到 git restore --staged 命令了:
git restore --staged README.md
[x] 再看 git status:
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: hello.py
new file: today.py
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
$ git checkout 5c59fbd
Note: switching to '5c59fbd'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 5c59fbd testing of first committing
$ git diff 5c59fbd
diff --git a/README.md b/README.md
index 7f118ff..e8233a7 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,2 @@
-Hello, Git!
\ No newline at end of file
+Hello, Git!
+this is the first change to README.md.
\ No newline at end of file
diff --git a/hello.py b/hello.py
new file mode 100644
index 0000000..735bdcc
--- /dev/null
+++ b/hello.py
@@ -0,0 +1 @@
+print('Hello world!')
\ No newline at end of file
diff --git a/today.py b/today.py
new file mode 100644
index 0000000..26624e2
--- /dev/null
+++ b/today.py
@@ -0,0 +1,2 @@
+from datetime import datetime
+print(datetime.now().strftime('今天是%Y年%月%d日'))
\ No newline at end of file
[x] 比较两个指定的 commit:
git diff 5c59fbd 6b9e427
结果如下:
$ git diff 5c59fbd 6b9e427
diff --git a/hello.py b/hello.py
new file mode 100644
index 0000000..735bdcc
--- /dev/null
+++ b/hello.py
@@ -0,0 +1 @@
+print('Hello world!')
\ No newline at end of file
diff --git a/today.py b/today.py
new file mode 100644
index 0000000..26624e2
--- /dev/null
+++ b/today.py
@@ -0,0 +1,2 @@
+from datetime import datetime
+print(datetime.now().strftime('今天是%Y年%月%d日'))
\ No newline at end of file
3. 了解非常重要的分支(branch)概念及其在协同中的用法
[x] 将以下内容朗读 3 遍:
tag 和 branch 其实都是指向 commit 的指针,区别在于 tag 指向一个固定的 commit,而 branch 会随着你的操作始终跟着最新的 commit。
[x] git tag 命令处理与 tag 有关的操作。如果不带任何参数执行 git tag 会输出仓库中存在的所有 tag,如果我们想在目前的最新的 commit 上打一个标签 v1.0,表示这是我们的 1.0 版本的状态,可以这么做:
[x] 由于我们现在需要尽快修复 bug,所以我们需要切换到新创建的 bug/fix1 分支(切换分支其实就是让 HEAD 指针指向该分支),这需要用 checkout 命令:
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on master
$ git checkout bug/fix1
Switched to branch 'bug/fix1'
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on bug/fix1
这时候 HEAD 指向的 bug/fix1 分支指针就会跟着我们提交的新 commit 走了。
ls
[x] 修复 bug:在 README.md 加入一行 “fix bug.”
[x] 查看状态
$ git status
On branch bug/fix1
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
[x] 将修改的 README 添加至 暂存区域,而后提交
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on bug/fix1 [!]
$ git add README.md
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on bug/fix1 [+]
$ git status
On branch bug/fix1
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: README.md
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on bug/fix1 [+]
$ git commit
[bug/fix1 9caf512] fix bug.
1 file changed, 2 insertions(+), 1 deletion(-)
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on bug/fix1
$ git status
On branch bug/fix1
nothing to commit, working tree clean
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on bug/fix1
$ git checkout master
Switched to branch 'master'
xuzhengfu at xuzhengfudeiMac in ~/Code/learn-git on master
[x] 从 team repo 同步所有 branch 及 commit:git fetch origin
$ git fetch origin
fatal: 'origin' does not appear to be a git repository
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
[x] Adding a new remote, use the git remote add command on the terminal, in the directory your repository is stored at. The git remote add command takes two arguments:
1. 了解 git 的一些最核心的基本概念和术语
1.1 了解 “工作目录”
1.2 了解 “仓库”
1.3 了解 “暂存区域”
1.4 了解 “检取”
1.5 了解 “本地仓库和远程仓库”
2. 跟着指引一步步地操作来熟悉 git 的基本用法
2.1 确认已经按照之前的指引配置好了你的系统
[x] 命令行界面:terminal
[x] 软件包管理工具
[x] VSCode
[x] git
2.2 在使用之前对 git 进行一些基本设置
结果如下:
2.3 基本操作
最后一个 pwd 命令会打印出你当前所在目录供确认,这就是我们的工作目录(working directory),里面还没有文件。
这个命令成功后会提示已经在当前目录下的
.git
子目录下初始化了一个空的 repo。ls
来查看是看不到这个.git
目录的,因为.
打头的目录是隐藏的,我们可以用ls -la
来显示它。结果如下:
这个
.git
目录下就是我们的版本仓库,使用 git 的特定数据格式保存。这也就意味着,我们的工作目录已经成为一个“由 git 进行版本控制”的目录,我们在这里做的任何事情都会被 git 跟踪,也可以作为版本提交到 repo 中去。git status
命令将显示目前工作目录的状态,比如有没有文件被修改,目前还什么都没有。这个命令对我们初学者很有用,我们应该养成习惯经常执行一下,看看在 git 的视角发生了什么。git status
可以看到下面的提示:git add
这个命令一般用来把有变化的文件加入待提交的“暂存区域(staging area)”,但对 untracked files 它具有双重功效,先将其加入到版本管理中(从 untracked 变成 tracked),再加入 staging area。git status
可以看到下面的提示:回到命令行可以看到执行结果:
git status
可以看到:code .
用 VSCode 打开当前目录,VSCode 会列出当前目录下所有文件(也就是刚才创建的 README.md),我们可以在 VSCode 里新建几个文件,里面填入一些内容,比如可以创建两个 Python 的程序源文件:hello.py:
today.py:
git status
可以看到类似下面的信息:[x] 第一段 Changes not staged for commit: 列出的是已经加入版本仓库但有了新变化的文件(README.md),如果我们发现改动是误操作,希望恢复到该文件上一个 commit 的状态可以使用这个命令:
git restore README.md
;或者旧版本的命令git checkout -- README.md
。git checkout
从版本仓库中取得一个文件的指定版本,然后覆盖到工作目录中。命令后面可以指定一个 commit id,上面我们用--
就表示从仓库里最新的一个 commit 中取,最后是要取出的文件路径(当前目录下 README.md 文件)。运行上面的命令会废弃掉(discard)刚才对 README.md 做的修改。[x] 假设你没有执行上一步的 discard,那么,我们可以把所有变化都加入 staging area:
这个命令中的
.
表示将当前目录及其下面变化的所有文件都加入到 staging area。git status
:git restore --staged
命令了:git status
:git commit
命令来提交那两个新加的 Python 文件,输入 commit message 之后提交成功。git status
看看状态。2.4 查看版本的历史记录
结果如下:
[x] 看看你的工作目录,是不是回到了你最初提交 README.md 一个文件的状态?新加入的文件和对 README.md 的修改都不见了。
[x] 所有的修改记录都还在 repo 里,现在可以用下面的命令回到当前:
[x] 一切又回到了最新的状态。
[x] 比较两个历史状态之间的差别,比较指定 commit 和工作目录当前状态:
q
键退回到命令行界面。结果如下:结果如下:
3. 了解非常重要的分支(branch)概念及其在协同中的用法
git tag
命令处理与 tag 有关的操作。如果不带任何参数执行git tag
会输出仓库中存在的所有 tag,如果我们想在目前的最新的 commit 上打一个标签 v1.0,表示这是我们的 1.0 版本的状态,可以这么做:[x] 这时再执行
git log
可以看到最新的 commit 后面出现了tag: v1.0
的字样,表示在这个 commit 上打上了一个名叫 “v1.0” 的标签,以后我们就可以用这个标签来引用这个 commit,而不需要用又长又没有实际意义的 commit id。[x] 我们还可以给某个更早的 commit 打标签,在标签名后面加上 commit id 即可,比如:
[x] 用
git tag -d v1.0 v0.9
删除标签。[x] 将以下内容朗读 3 遍:
git branch
在当前 commit 上创建分支,注意创建分支并不会自动切换到新创建的分支,目前我们还工作在 master 分支,HEAD 指针指向 master 分支bug/fix1
分支(切换分支其实就是让 HEAD 指针指向该分支),这需要用checkout
命令:这时候 HEAD 指向的
bug/fix1
分支指针就会跟着我们提交的新 commit 走了。 ls[x] 修复 bug:在 README.md 加入一行 “fix bug.”
[x] 查看状态
bug/fix1
分支上的工作告一段落,需要切回主分支:现在轮到 master 分支指针跟着我们提交的新 commit 走了。
[x] 在合适的时间,团队里某位成员可以进行分支合并,假定是把
bug/fix1
分支合并到master
分支(实际上可以把任意分支合并到任意分支):git fetch origin
原因在于:所有 branch 及 commit 都在版本仓库当中,那版本仓库在哪儿呢?在
.git
子目录下。那.git
子目录又在哪儿呢?就在你使用git init
命令的那个目录中——它就在我们的计算机里。我还没有把它上传到 GitHub 作为一个 远程仓库。git checkout master
bug/fix1
分支合并到master
分支:git merge bug/fix1
4. 了解如何利用 GitHub 来简化分享与协同
[x] 1. 在 GitHub 创建一个新的 repo,然后把你在自己本地已经建好的 repo 放上去。
[x] 在你的 GitHub “New” 一个仓库;
[x] Adding a new remote, use the git remote add command on the terminal, in the directory your repository is stored at. The git remote add command takes two arguments:
[ ] 2. 把 GitHub 上已有的 repo 克隆到自己本地,可能还会对这个 repo 做出一些内容贡献。
[ ] 在你看中的 repo 首页按那个绿色的 “Clone or download” 按钮,拷贝下面文字框里的 repo 地址;
[ ] 然后在你的命令行界面贴到
git clone
命令后面执行就行了。无论哪种场景,最终的情况都一样,就是你的本地有一个仓库对应到 GitHub 上某个仓库,你可以在本地工作,并通过 GitHub 与这个世界上任何人进行合作!
Reference
Logging
2020-02-11 20:16:29 initialize