目录
参考(强烈推荐):廖雪峰的 Git 教程。
输入 git
查看是否已安装。
如果没有安装,安装指令: sudo apt-get install git
Git 是分布式版本控制系统,因此每个机器都需要有对应的 ID :名字和邮箱地址。
我们来设置本台机器的信息:
git config --global user.name "Name"
git config --global user.email "Email address"
--global
的意思是:这台机器上的所有 Git 仓库都使用该信息。
假设现在有一个文件夹,路径为 /home/xing/MEQE_local
在该目录下,执行: git init
,使得该目录成为 Git 可以管理的仓库。
此时会产生一个隐藏的 .git
目录,可以用 ls -ah
查看到。
该目录是 Git 用以跟踪版本库的,千万不要手动修改。
版本控制系统只能跟踪文本文件的改动,比如 txt ,网页和代码。
对于图片、视频等二进制文件,系统无能为力,只能知道图片大小从 100KB 变成了 120KB 等。
有两点注意:
假设我们在该目录下创建了一个 txt 文件,名为 readme.txt
。
该文件只有一行内容: Git is free software.
第一步,用命令 git add
告诉 Git ,把文件添加到仓库:
git add readme.txt
提示: 1 file changed, 1 insertion(+)
。因为添加了一个文件,写了一行。
第二步,正式提交修改:
git commit -m "create a readme file."
如果是多个文件,可以这么操作:
git add file0.txt
git add file1.txt file2.txt file3.txt
git commit -m "add 4 files."
假设我们加上了新的一行: Keep moving!
此时运行 git status
查看状态,会显示:
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
这说明: Git 检测到变动: readme.txt
,但是没有准备 (staged) 提交修改 (for commit)的变动 (changes) 。
我们可以用 git diff
查看变动内容:
diff --git a/readme.txt b/readme.txt
index f5b143e..a48528a 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1 +1,2 @@
Git is free software.
+Keep moving!
最后一行告诉我们,增加了一行 Keep moving!
。
确认以后,我们再提交到仓库。方法同上一节两步。第一步,要求添加至仓库:
git add readme.txt # 没有任何输出
但此时再查看状态,就不一样了:
git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: readme.txt
确认将要正式 commit
的文件只有 readme.txt
,那么就可以正式提交了。
再次查看状态,就显示没有文件需要 commit
,并且 working tree clean
。什么意思?后面说。
每一次 commit
,实际上就是一次存盘,或者说一次快照。
我们可以用 git log
命令查看历史变动:
[master b87e2c5] add a new line.
1 file changed, 1 insertion(+)
xing@xing:~/MFQE_local$ git log
commit b87e2c5fd623591a510a4873aecdc43793de392e
Author: xing <ryanxingql@foxmail.com>
Date: Wed Nov 7 21:41:48 2018 +0800
add a new line.
commit f5c7b7bb1df2455cec90a092ecd231dd8e395bc3
Author: xing <ryanxingql@foxmail.com>
Date: Wed Nov 7 20:57:11 2018 +0800
create a readme file
如果我们想让每一次变动只显示一行,可以这么做: git log --pretty=oneline
:
b87e2c5fd623591a510a4873aecdc43793de392e add a new line.
f5c7b7bb1df2455cec90a092ecd231dd8e395bc3 create a readme file
前面一串是 commit id
,这么复杂的原因,是考虑到分布式修改的使用场景,不能简单地用 1,2,3,...
甚至还可以用可视化工具查看。
我们准备把 readme.txt
回退到最初版本,写法是: git reset --hard HEAD^
再查看文件时,已经恢复成最初的模样!
如果想恢复到上上个版本,就是 HEAD^^
。如果是往上 100 个,那就是 HEAD~100
。
--hard
参数后面再讲。
此时再查看历史记录:
Author: xing <ryanxingql@foxmail.com>
Date: Wed Nov 7 20:57:11 2018 +0800
create a readme file
完了,记录没了,回不去了?
且慢,只要命令行没关,你就可以找到原来的 commit id = b87e2c5fd623591a510a4873aecdc43793de392e
,然后指定 id 回退:
git reset --hard b87e2c5fd623591a510a4873aecdc43793de392e
又恢复成最后的样子了!其实可以只输入 b87e
,Git 会自动去找。
Git 的回退速度非常快,因为本质上是在 Git 内部完成了 HEAD
指针的移动。
HEAD
指针永远指向当前版本。
如果命令行关闭了甚至关机了……那么我们还可以用 git reflog
来找回 id ,它记录了完整的 log :
b87e2c5 HEAD@{0}: reset: moving to b87e2c5fd623591a510a4873aecdc43793de392e
f5c7b7b HEAD@{1}: reset: moving to HEAD^
b87e2c5 HEAD@{2}: commit: add a new line.
f5c7b7b HEAD@{3}: commit (initial): create a readme file
我们看到的目录 /home/xing/MEQE_local
,实际上就是工作区 working directory 。
我们最开始提到的 .git
隐藏目录,不属于工作区,而是版本库 repository 。
其中最重要的就是暂存区 stage (index) ,还有 Git 自动为我们创建的第一个分支 master ,以及指向 master 的指针 HEAD 。
IMAGE 1
如图,这就明白 add 和 commit 的工作原理了。
第一步 add
,实际上是把文件从工作区添加到暂存区;
第二步 commit
,实际上是把文件从暂存区提交到当前分支。
分支和 HEAD
后面讲。
所以我们说:我们可以连续 add
很多文件到暂存区,最后一次性 commit
到分支里。
实验:我们把 readme.txt
的第二行删掉,再创建一个 LICENSE.txt
文件。然后再查看状态:
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
Untracked files:
(use "git add <file>..." to include in what will be committed)
LICENSE.txt
no changes added to commit (use "git add" and/or "git commit -a")
系统检测到: readme.txt
改动了但没有 commit
,而工作区里的 LICENSE.txt
甚至还没有 add
到暂存区,因此没有被“跟踪”。
换句话说,暂存区里的 readme.txt
就是被跟踪的。
我们分别对这两个文件都执行 add
以后,状态显示:
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: LICENSE.txt
modified: readme.txt
图就不看了,两个文件现在都在暂存区里。
然后 git commit -m "commit 2 files."
,搞定!此时暂存区就空了。
什么叫 working tree clean
?即提交时,没有对工作区进行新的改动。
现在的 readme.txt
只有一行。
假设我们:
readme.txt
中增加一行;add
没有 commit
;commit
可以猜到,尽管真实的文件已经修改了两回,但只有第一次修改通过 add
放入到暂存区,第二次修改没有被放入暂存区。
因此如果查看状态,会显示:
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: readme.txt
no changes added to commit (use "git add" and/or "git commit -a")
这就是管理修改,而不是管理文件的例子。
我们可以通过 git diff HEAD -- readme.txt
命令,查看 工作区文件 和 版本库中的最新版本 的区别:
diff --git a/readme.txt b/readme.txt
index 80cc1f9..785e827 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,3 @@
Git is free software.
Hello
+Hello again
如果我们错误修改了工作区文件,并且 commit
了,那么撤销修改只能用版本回退的方法。
如果我们错误修改了工作区文件,但还没有 add
,那么最直接的办法就是:手动删除错误变动。
除此之外,我们可以用 git checkout -- readme.txt
操作,撤销工作区文件的变动。
有两种情况:
commit
了。commit
(仅被 add
)。总之就是撤销一步工作区的修改,无论上一次修改是否 commit
到了分支。
--
的作用是:保持在当前分支。否则会切换到另一分支。后面讲。
如果我们错误修改了工作区文件,并且已经 add
了。此时需要两步。
第一步,用 reset
操作撤销 add
更改:
git reset HEAD readme.txt
这里的 HEAD
声明:回退到暂存区历史最新版本。
第二步,撤销工作区文件操作。方法上面说过了,就是 git checkout -- readme.txt
。
最后,如果我们不仅 commit
了,而且还推送到远程版本库了,那就凉了。后面讲。
假设我们在文件管理器中把 LICENSE.txt
删除了: rm LICENSE.txt
此时查看状态会显示 deleted 。
如果确认不是误删,我们可以从版本库中删除对应文件: git rm LICENSE.txt
,注意也要 commit
。
当然了,add
再 commit
也可以,因为删除也是一种对文件的修改。
如果是误删,那么此时由于还没有 add
,因此我们可以用 checkout
撤销误操作。
本质上是用版本库的最新文件,替换工作区版本。
如果只是本地版本控制系统(或集中式),那么 Git 相较于 SVN 没有任何优势。
但作为分布式管理系统, Git 有众多优势。远程仓库是第一个杀手锏。
Git 的同一个仓库,可以部署到不同的机器上。
对个人玩家(比如我)而言,我们不会在一台机器的多个硬盘上进行同步,而是在个人电脑和远程服务器上进行同步。
我们可以自行搭建一台运行 Git 的服务器,但更多时候,我们会借助 GitHub 等 Git 仓库托管服务平台。
注意,本地 Git 仓库和 GitHub 仓库之间的传输是通过 SSH 加密的,因此需要以下准备:
ssh-keygen -t rsa -C "youremail@example.com"
,无需设置密码。.ssh
目录,里面有公钥 id_rsa.pub
和 私钥 id_rsa
。id_rsa.pub
文件的内容。原因是,远程仓库需要知道是本人提交的推送,而 Git 支持 SSH 协议。
如果我们有很多电脑,那就把这些设备的公钥都设置好。
在网站上操作。
假设我们现在有一个文件夹: /home/xing/Desktop/MFQE_code
,并将其设置为 Git 可管理的本地仓库。
我们将其和网站上的 MFQE 仓库关联。在当前目录下运行:
git remote add origin https://gitee.com/XINGRYAN/MFQE.git
后面的地址别搞错了,否则可能会关联到别人的远程库,但由于公钥不在其列表中,因此无法推上去。
添加后,远程仓库名就是 origin ,这是 Git 默认的叫法,可改,但一看到 origin 就知道是远程库。
我们写一个 README.md
,将其推送到远程库上。
推送前,我们应该先 add
commit
。
然后执行:
git push -u origin master
# Counting objects: 7, done.
# Delta compression using up to 8 threads.
# Compressing objects: 100% (3/3), done.
# Writing objects: 100% (7/7), 593 bytes | 0 bytes/s, done.
# Total 7 (delta 0), reused 0 (delta 0)
# remote: Powered by Gitee.com
# To https://gitee.com/XINGRYAN/MFQE.git
# * [new branch] master -> master
# Branch master set up to track remote branch master from origin.
意思是:将当前分支 master
推送到远程。
由于远程库是空的,因此第一次推送时,我们加上 -u
参数,不仅完成了推送,而且还将本地和远程的 master
分支关联起来,在以后的推送和拉取时可以简化命令。
实际上 Git 支持 多种协议,包括 SSH 和 https 。上面用到的正是 https 。
如果我们本地什么都没有,希望从远程库上克隆下来一个库,那么我们可以这么操作。
首先,假设有一个库名为 gitskills
,属于 michaelliao 的,里面只有一个 README.md
。那么我们执行:
git clone git@github.com:michaelliao/gitskills.git
# Cloning into 'gitskills'...
# remote: Counting objects: 3, done.
# remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 3
# Receiving objects: 100% (3/3), done.
此时在本地的 gitskills
目录下,就有了一个完全相同的库,含 README.md
。
原文:https://www.cnblogs.com/RyanXing/p/10460447.html