Git操作

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

http://git-scm.com/book/zh/v1

###LearnGitBranching ###
强烈推荐
http://pcottle.github.io/learnGitBranching/

Austin wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!