通过实际操作学习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/