原文地址:zeroturnaround
编译:FireFrank
原文地址:http://www.freebuf.com/sectool/98396.html
我们这次介绍最成功的源码管理工具——Git!这是一个非常棒的工具,它使用了拥有强大功能和选项的命令行界面,这就导致你需要记住并能够在必要时回忆起这些命令。
如果你和我一样,记东西就像负重蚂蚁一样昏昏沉沉,你可能非常需要我们的帮助!下面,我们将会为你展示一整页常用git命令,有了它你的工作会变得愉快的多。OK,言归正传,你可能已经点击了下面的链接查看完整的git命令,如果你没有点击,你可能缺少了一些冒险精神哦。
现在和我一起开始Git之旅。我们会以一个典型的SSM工作流程为例展示一些最佳做法。下面我们将介绍更多命令的详情。
我们应该从哪里开始?
好啦,现在课程开始!在最开始的时候,Git创建init并clone。这两个命令会从头开始创建一个能够管理你源码的仓库。这两个命令当然不同,init
命令用于从scrach创建仓库,而clone即字面上的clone,使用该命令把项目从现有的仓库中复制到你运行的目录。一旦完成这些操作,我们就可以真正的工作流程啦!在ZipRebel项目上有两个例子:
$ git init myProject
Initialized empty Git repository in /Users/sjmaple/myProject/.git/
clone命令:
$ git clone https://github.com/zeroturnaround/ziprebel.git
Cloning into 'ziprebel'...
remote: Counting objects: 94, done.
remote: Total 94 (delta 0), reused 0 (delta 0), pack-reused 94
Unpacking objects: 100% (94/94), done.
Checking connectivity... done.
Branching
举个例子,如果我们要创建新功能,我们应该考虑创建一个新的分支(branch)储存新功能代码。我觉得这样做最重要的一点就是保持新功能代码能够和旧代码分离,你可以轻松的从各个分支(branch)转换并且不会污染你的mater代码。所以我们怎么创建分支呢?这点非常容易!只需要使用branch
命令,再起个名字就好啦,如下所示:
$ git branch feature/unzip
在这种情况下,我们需要理智命名,这样我们就可以通过看branch名称得知这部分代码的功能,比如我们为ZipRebel项目创建unzip
功能。虽然这个命令没有反馈,但是我们可以使用相同的命令查看所有的分支(branch),这个branch
命令不带参数:
$ git branch
feature/unzip
* master
我们通过branch
命令还可以做其他事情。首先,我们可以看到我们新创建的分支,其次,我们当前处在的活跃分支是master
,而不是新的分支。顺便说一句,你可以查看所有的分支,甚至可以通过增加参数查看远程分支。我们想要跳到功能/unzip
分支来开始code我们的新功能,我们使用checkout
命令转换分支:
$ git checkout feature/unzip
Switched to branch 'feature/unzip'
这个命令用于转换分支,更新工作目录,其代码基础不同。就像我们刚刚创建的分支就没有任何更新。
改变的时候到了
现在让我们更改代码。我们要使用术语来解释并指出一个个状态并充分理解这些状态。看下面这张图片:
是不是很漂亮!我们工作目录中的文件包含所有的文件,而这些文件会被随时编辑修改,但是事实是直到你执行git命令之后,这些内容才更改。现在让我们看看你项目中所有文件的状态,使用下面这些已经在你脑子中根深蒂固的命令:
$ git status
On branch feature/unzip
nothing to commit, working directory clean
让我们在工作流上进行一些修改,然后看看更新状态消息是如何进行的。只要编辑一些文件,但是只执行git status
,结果如下:
$ git status
On branch feature/unzip
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: src/main/java/org/zeroturnaround/ziprebel/ZipRebel.java
modified: src/test/java/org/zeroturnaround/ziprebel/ZipRebelTest.java
no changes added to commit (use "git add" and/or "git commit -a")
这些内容告诉我们我们已经修改了一些文件,但是并没有将修改添加到staging
(staging就是索引),为下一步commit做好准备。我们接下来使用git add commit
命令将文件单独或者成组引用添加到staging
,或者stage这些文件,或者添加一个包含所有修改过文件的wildcard
。我们现在执行后一种操作:
$ git add .
再次执行git status
命令,你会看到成功了:
$ git status
On branch feature/unzip
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: src/main/java/org/zeroturnaround/ziprebel/ZipRebel.java
modified: src/test/java/org/zeroturnaround/ziprebel/ZipRebelTest.java
现在我们看到的git承认修改过的文件作为要提交修改的文件。一页就可以完成你的版本控制系统的感觉是不是相当不错?你会看到在输出这里的HEAD token
。HEAD
是一个指针或者引用当前分支。在这一点上,我们可以通过对文件运行git reset
选择来unstage
文件,做出进步一修改或者commit我们的修改到本地资源。让我们执行后者:
$ git commit -m "Added unzip capability"
[feature/unzip 05db2cc] Added unzip capability
2 files changed, 2 insertions(+), 2 deletions(-)
如果我们知道只做出了很小的修改不用做出其他commit,我们可以在同一个命令里既执行add
操作又执行commit。下面的命令就适用于我们已经修改了但不在阶段环境中的文件:
$ git commit -am "Added unzip capability"
[feature/unzip 8c10510] Added unzip capability
2 files changed, 2 insertions(+), 2 deletions(-)
-a
标志将添在执行commit之前把所有跟踪文件从工作目录添加到临时执行。(请注意,你工作目录中创建的文件在手动添加之前都不会被追踪)。等等,commit是什么意思?这是一个很大的问题!本质上一个git commit记录你的修改快照,标记你的姓名、电子邮箱和commit id的commit信息。
在上面的例子中,我们拿id 05db2cc 和 8c10510 作为commit自理。这些可以在之后编码时遇到故障排除、事故追踪或故障查明时使用。说到事故追踪,git blame
是一个非常有趣的命令,它在文件中使用关于谁对代码做出最后的修改,提交了哪些修改等做出注释。这样可以输出很多文本,因此考虑使用一个行范围-L
标志进行限制输出。
有什么不同呢?
当一个文件的不同内容储存在很多个地方,了解不同位置有什么变化是很重要的。举个例子,我想知道我的工作区文件和我的临时文件有什么区别。这里有很多选项可供选择。事实上,diff
命令在很多情况下都非常有用。我们下面的内容会介绍一些diff
命令。
首先,让我们先思考何如比较你工作目录和你临时存储区的区别。做到这点非常容易!只需要输入git diff
。如果你想要比较你的本地仓库和临时存储区,你可以使用git diff –cached
。你甚至可以使用commit ids
比较几次不同的提交,比如:git diff 05db2cc 8c10510
。这是已给非常给力的工具,所以确保使用git diff –help
来查看所有功能选择最适合你的使用情况。
最后,一旦你已经完成了新分支的开发,你需要把它合并到主分支。所以首先你要进入你想要合并的分支中。在这种情况下,我们会运行git checkout master
。接下来,我们将进行分支合并工作。我们运行git merge feature/unzip
。一切顺利的话,我们的代码会自动合并,我们不需要担心这件事儿!但是,合并可能不会一帆风顺,可能会出现一些必须解决的冲突!git status
命令会帮助你理解哪里存在冲突。如果你打开文件,你会注意到这些标记:<<<<<<<
, >>>>>>>
, 和=======
,这些标记会围绕冲突,每个分支正在努力完成的修改。
现在,我们开始学习fork
命令啦。我们应该做什么呢?你写好了代码,想要删除冲突代码保证进行新的commit提交到主分支。另外,如果另一个开发人员写了一份更棒的代码,你可能想要选择他的代码进行提交。更可能出现的情况是,你需要创建两个修改的代码,然后把代码合并到主分支。在任何情况下,你都需要修复文件,之后添加并commit这些更改,这样你才能享受你高潮的解决冲突的能力带来的美好结果。
让我们远程操作!
目前为止,包括我们仓库更改在内的所有更改都是本地的。我们甚至不需要提到远程仓库,现在让我们回到文章最开始的地方,从git clone
开始将其。在某些阶段中,我们需要同步本地和远程仓库,并且我们需要一些命令帮助我们实现同步:pull
, push
, fetch
。
让我们从这个问题开始:如果我们有一个过时的本地仓库会发生什么?如果其他人在远程仓库中更新了新功能、修复了bug或者修改了代码,那我们的本地仓库肯定过时了。我们需要抓住这些变化,事实上我想要说可以用pull
或者fetch
,但是我不想重新使用这些命令的名称就能最新最棒的代码更新我们的本地仓库。入侵性最小的方式就是使用fetch
命令,它会从远程仓库中抓起所有最近的commit,然后把这些导入到同一个远程反之中。
但是值得注意的是,fetch
并不会把这些commit添加到你工作空间的本地branch中,你可以使用之前提到的git branch -av
命令查看远程分支。你在这里还可以选择手动合并分支。或者,使用git pull –rebase
命令,它会先执行git fetch
命令,再执行git rebase
命令。但是妈个鸡,什么是rebase?它是一种机制,这种机制允许你在传入的commit顶部应用本地commit,而不是简单的平行的两条线合并。
最后,我们介绍一下push
命令,它是fetch
的对立命令。我们只是简单的从我们的本地仓库把代码传到远程仓库。注意,总有一些文件会被重写,千万小心!
总结
希望这些命令解释能对你有用。我们很希望得到你的git技巧哦,在评论中写下你的技巧和窍门吧!