通过实际操作学习Git
1.基本操作
git init ——初始化仓库
要使用Git进行版本管理,必须先初始化仓库。Git是使用git init命令进行初始化的。请实际建立一个目录并初始化仓库。
如果初始化成功,执行git init命令的目录下就会生成.git目录。这个目录里存储着管理当前目录内容所需的仓库数据。
在Git中,我们将这个目录的内容称为“附属于该仓库的工作树”。
git status——查看仓库的状态
git status命令用于显示Git仓库的状态。这个命令十分常用,务必牢记。
git add——向暂存区添加文件
要想让文件成为Git仓库 的管理对象,就需要用git add命令将其加入暂存区(Stage或Index)中。暂存区是提交之前的一个临时区域。
将README.md文件加入到暂存区后,git status命令显示的结果发生了变化。可以看到,README.md文件显示在Changes to be committed中了。
git commit——保存仓库的历史记录
git commit命令可以将当前暂存区中的文件实际保存到仓库的历史记录中。通过这些记录,我们就可以在工作树中复原文件。
记述一行提交信息

-m参数后的”First commit”称作提交信息,是对这个提交的概述。
记述详细提交信息
如果想要记述得更加详细,不加-m,直接执行git commit命令。
终止提交
想终止提交,直接关闭编译器。
查看提交状态

当前工作树处于刚刚完成提交的最新状态,所以结果显示没有更改。
git log——查看提交日志
git log命令可以查看以往仓库中提交的日志。
只显示提交的第一行
如果只想让程序显示第一行简述信息,可以在git log命令后面加上--pretty=short。
只显示制定目录、文件的日志
git log命令后加上目录名。如:
$git log README.md
显示文件的改动
如果想查看提交所带来的改动,可以加上-p参数,文件的前后差别就会显示在提交信息之后。
$git log -p
$git log -p README.md
git diff
git diff命令可以查看工作树、暂存区、最新提交之间的差别。
这里解释一下显示的内容。”+”号标出的是新添加的行,”-“标出的是被删除的行。
用$git add README.md命令将文件添加入暂存区。
查看工作树和最新提交的差别
要查看与最新提交的差别,请执行以下命令。
不妨养成这样一个好习惯:在执行git commit之前先执行git diff HEAD,查看本次提交与和上次提交之间有什么差别,等确认完毕后再进行提交。这里的HEAD是指向当前分支中最新一次提交的指针。
查看第二次提交是否成功:
分支操作
在进行多个并行作业时,我们会用到分支。
git branch——显示分支一览表
git branch命令可以将分支名列表显示,同时可以确认当前所在分支。
*代表当前所在分支,也就是说我们正在master分支下进行开发。
git checkout -b ——创建、切换分支
如果想以当前的master分支为基础创建新的分支,我们需要用到git check -b命令
切换到feature-A分支并进行提交

这时再来查看分支列表,会显示我们处于feature-A分支下。
在这个状态下像正常开发那样修改代码、执行git add命令并进行提交的话,代码就会提交至feature-A分支。像这样不断对一个分支进行提交的操作,我们称为”培育分支”。
切换到master分支
现在我们再来看一下master分支有没有受到影响。首先切换至master分支。
然后查看README.md文件,会发现仍然保持原有的状态,并没有添加文字。feature-A分支下的更改不会影响到master分支,这正是开发中创建分支的优点。只要创建多个分支,就可以在不互相影响的情况下同时进行多个功能的开发。
切换回上一个分支
现在,我们切换回feature-A分支。
git merge——合并分支
接下来,我们假设feature-A已经实现完毕,想要将它合并到主分支mater中。首先切换到master分支。
然后合并feature-A分支。为了在历史记录中明确记录下本次分支合并,我们需要创建和并提交。因此,在合并时加上--no-ff参数。
$git merge --no-ff feature-A
随后编辑器会启动,用于录入和并提交的信息。
git log –graph——以图表形式查看分支
用git log --graph命令进行查看的话,能很清楚的看到特性分支(feature-A)提交的内容已经被合并了。
用于图表形式输出提交日志,非常直观,务必牢记。
更改提交的操作
git reset——回溯历史版本
Git的另一特征便是可以灵活操作历史版本。借助分散仓库的优势,可以在不影响其他仓库的前提下对历史版本进行操作。
回溯到创建feature-A分支前
回溯,创建feature-B的特性分支。
要让仓库的HEAD、暂存区、当前工作树回溯到指定状态,需要用到git rest --hard命令。
只要提供目标时间点的哈希值,就可以完全恢复至该时间点的状态。执行下面命令:
创建fix-B分支
现在我们来创建特性分支(fix-B)。
我们在README.md中添加一行文字
然后直接提交README.md文件。
推进至feature-A分支合并后的状态
首先恢复到feature-A分支合并后的状态,不妨称这一操作为”推进历史”。
git log命令只能查看以当前状态为重点的历史日志。所以这里要使用git reflog命令,查看当前仓库的操作日志。在日志中找出回溯历史前的哈希值,通过git reset hard命令恢复到回溯历史前的状态。
首先执行git reflog命令,查看当前仓库执行过的操作的日志。
在日志中,我们看到Git命令的执行记录。只要不进行Git的GC就可以通过日志随意调取近期的历史状态。务必牢记本部分。
从上面数第四行表示feature-A特性分支合并后的状态,对应哈希值为5c4e29a。我们将HEAD、暂存区、工作树恢复到这个时间点的状态。
$ git checkout master
Switched to branch 'master'
$ git reset --hard 5c3e29a
HEAD is now at 5c3e29a Merge branch 'feature-A'
之前我们使用git reset --hard命令回溯了历史,这里又再次通过它回溯前的历史状态。
消除冲突
现在只要合并fix-B分支,就可以得到我们想要的状态。进行合并操作。
$ git merge --no-ff fix-B
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
这时,系统告诉我们README.md文件发生了冲突(conflict)。系统在合并README.md文件时,feature-A分支更改的部分与本次想要合并的fix-B分支更改的部分发生了冲突。
查看冲突部分并将其解决
用编辑器打开README.md文件,就会发现内容变成下面这个样子。
# Git教程 #
<<<<<<< HEAD
- feature-A
=======
-fix-B
>>>>>>> fix-B
=======以上的部分是当前HEAD的内容,以下的部分是要合并的fix-B分支的内容。我们在编辑器中将其改成想要的样子。
# Git教程 #
- feature-A
-fix-B
提交解决后的结果
冲突解决后,执行git add命令与git commit命令。
$ git add README.md
$ git commit -m "Fix conflict"
[master 55caf1a] Fix conflict
git commit –amend——修改提交信息
要修改上一条提交信息,可以使用git commit --amend命令。
git rebase -i——压缩历史
在合并特征分支前,如果发现已提交内容中有些拼写错误等,不妨提交一个修改,然后将这个修改包含到前一个提交之中,压缩成一个历史记录。这是个常用的技巧。
创建feature-C分支
首先创建feature-C特性分支。
我们在README.md文件中添加一行文字,并故意留下错误。
提交这部分内容,我们用git commit -am完成这两步操作。
$ git commit -am "Add feature-C"
[feature-C a0c6d59] Add feature-C
1 file changed, 1 insertion(+)
修正拼写错误
自行修正README.md,修正后的差别如下:
$ git diff
diff --git a/README.md b/README.md
index f19dea9..7a65e4f 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Git教程 #
- feature-A
-fix-B
--faeture-C
+-feature-C
然后进行提交
$ git commit -am "Fix typo"
[feature-C 834a496] Fix typo
1 file changed, 1 insertion(+), 1 deletion(-)
错字漏字等失误称作typo
更改历史
将”Fix typo”修正的内容与之前一次的提交合并,在历史记录中合并为一次 完美的提交。我们要用到git rebase命令。
pick a0c6d59 Add feature-C
pick 834a496 Fix typo
# Rebase 55caf1a..834a496 onto 55caf1a (2 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# 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.
#
# Note that empty commits are commented out
推送至远程仓库
Git是分散型版本管理系统。下面,我们开始接触远在网络另一头的远程仓库。远程仓库顾名思义,是我们本地仓库相对独立的另一个仓库。让我们现在GitHub上创建一个仓库,并将其设置为本地仓库的远程仓库。
git remote add——添加远程仓库
现在我们用git remote add命令将它设置成本地仓库的远程仓库。
$ git remote add origin git@github.com:CodingMaster1/git-tutorial.git
按照上述格式执行命令后,Git会自动将远程仓库的名称设置为origin(标识符)。
git push——推送至远程仓库
推送至master分支
如果想将当前分支下本地仓库的内容推送给远程仓库,需git push命令。
$ git push -u origin master
Enter passphrase for key '/c/Users/Andone/.ssh/id_rsa':
Counting objects: 16, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (16/16), 1.18 KiB | 0 bytes/s, done.
Total 16 (delta 2), reused 0 (delta 0)
To git@github.com:CodingMaster1/git-tutorial.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
像这样执行git push命令,当前分支的内容就会被推送至远程仓库origin的master分支。-u参数可以在推送的同时,将origin仓库的master分支设置为本地仓库当前分支的upstream(上游)。添加了这个参数,将来运行git pull命令从远程仓库获取内容时,本地仓库的这个分支就可以直接从origin的master分支获取内容,省去了另外添加参数的麻烦。
执行该操作后,当前仓库master分支的内容将会被推送到GitHub的远程仓库中。
推送至master以外的分支
除了master分支以外,远程仓库也可以创建其他分支。EX:我们在本地仓库中创建feature-D分支,将它以同名形式push至远程仓库。
$ git checkout -b feature-D
Switched to a new branch 'feature-D'
我们在本地仓库中创建了feature-D分支,现在将它push给远程仓库并保持分支名称不变。
$ git push -u origin feature-D
Enter passphrase for key '/c/Users/Andone/.ssh/id_rsa':
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 537 bytes | 0 bytes/s, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@github.com:CodingMaster1/git-tutorial.git
* [new branch] feature-D -> feature-D
Branch feature-D set up to track remote branch feature-D from origin.
现在在远程仓库的GitHub页面就可以查看到feature-D分支了。
从远程仓库获取
我们从实际开发者的角度出发,再另一个目录下新建一个本地仓库,学习从远程仓库获取内容的相关操作。
git clone——获取远程仓库
获取远程仓库
首先我们换到其他目录下,将GitHub上的仓库clone到本地。注意不要在同一个文件夹下。
$ git clone git@github.com:CodingMaster1/git-tutorial.git
Cloning into 'git-tutorial'...
Warning: Permanently added the RSA host key for IP address '192.30.252.130' to the list of known hosts.
Enter passphrase for key '/c/Users/Andone/.ssh/id_rsa':
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 22 (delta 2), reused 22 (delta 2), pack-reused 0
Receiving objects: 100% (22/22), done.
Resolving deltas: 100% (2/2), done.
Checking connectivity... done.
执行git clone命令后我们会默认处于master分支下,同时系统会自动将origin设置成该远程仓库的标识符。也就是说,当前本地仓库的master分支与GitHub端远程仓库(origin)的master分支的内容上是完全相同的。git
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/feature-D
remotes/origin/master
用git branch -a命令查看当前分支的相关信息。-a参数可以同时显示本地仓库和远程仓库的分支信息。
获取远程的feature-D分支
我们试着将feature-D分支获取至本地仓库。
$ git checkout -b feature-D origin/feature-D
Branch feature-D set up to track remote branch feature-D from origin.
Switched to a new branch 'feature-D'
-b参数的后面是本地仓库中新建的分支名称。例子中指定了origin/feature-D,也就是说以名为origin的仓库(这里指GitHub端的仓库)的feature-D分支为来源,在本地仓库中创建feature-D分支。
向本地的feature-D分支提交更改
现在我们假定我们是另一名开发者,我做一个新的提交。在README.md文件中添加一行文字,查看更改。
$ git diff
diff --git a/README.md b/README.md
index 7a65e4f..d46a355 100644
--- a/README.md
+++ b/README.md
@@ -3,3 +3,4 @@
-fix-B
-feature-C
+哈哈哈
按照之前的提交即可。
$ git commit -am "Add feature-D"
[feature-D 4509955] Add feature-D
1 file changed, 1 insertion(+)
推送feature-D分支
现在来推送分支。
$ git push
Enter passphrase for key '/c/Users/Andone/.ssh/id_rsa':
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 288 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:CodingMaster1/git-tutorial.git
834a496..4509955 feature-D -> feature-D
从远程仓库获取feature-D分支,在本地仓库中提交更改,再将feature-D分支推送回远程仓库,通过这一系列操作,就可以与其他开发者合作,共同培育feature-D分支,实现某些功能。
git pull——获取最新的远程仓库分支
现在我们回到原先的那个目录下。这边的本地仓库只创建了feature-D分支,并没有进行提交。这时我们就可以使用git pull命令,将本地仓库feature-D分支更新到最新状态。
$ git pull origin feature-D
Enter passphrase for key '/c/Users/Andone/.ssh/id_rsa':
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:CodingMaster1/git-tutorial
* branch feature-D -> FETCH_HEAD
834a496..4509955 feature-D -> origin/feature-D
Updating 834a496..4509955
Fast-forward
README.md | 1 +
1 file changed, 1 insertion(+)
GitHub端远程仓库中的feature-D分支已经是最新状态,所以本地仓库中的feature-D分支就得到了更新。今后只需要像平常一样在本地仓库进行提交再push给远程仓库,就可以与其他开发者同时在同一个分支中进行作业,不断给feature-D增加功能。
如果两人同时修改了同一部分的源代码,push时就很容易发生冲突。所以多名开发者在同一分支中进行作业时,为减少冲突情况的发生,建议更频繁的进行push和pull操作。
帮助学习的Git资料
Pro Git
###LearnGitBranching ###
强烈推荐
http://pcottle.github.io/learnGitBranching/