git

来源:互联网 发布:淘宝怎么开虚拟充值 编辑:程序博客网 时间:2024/06/06 04:16

git


什么是git?

Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。

git的安装

1.git在linux下的安装

sudo apt-get install git

2.git在windows下的安装
msysgit是Windows版的Git,从https://git-for-windows.github.io下载,然后按默认选项安装即可

git工作流程

一般工作流程如下:

  • 克隆 Git 资源作为工作目录。
  • 在克隆的资源上添加或修改文件。
  • 如果其他人修改了,你可以更新资源。
  • 在提交前查看修改。
  • 提交修改。
  • 在修改完成后,如果发现错误,可以撤回提交并再次修改并提交。

下图展示了 Git 的工作流程:
cmd-markdown-logo

git的工作区,暂存区和版本库

我们先来理解下Git 工作区、暂存区和版本库概念:

  • 工作区:就是你在电脑里能看到的目录。
  • 暂存区:英文叫stage,或index。一般存放在”git目录”下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
  • 版本库:工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系:
cmd-markdown-logo

  1. 图中左侧为工作区,右侧为版本库。在版本库中标记为 “index” 的区域是暂存区(stage, index),标记为 “master” 的是 master 分支所代表的目录树。
  2. 图中我们可以看出此时 “HEAD” 实际是指向master分支的一个”游标”。所以图示的命令中出现 HEAD 的地方可以用 master 来替换
  3. 当对工作区修改(或新增)的文件执行 “git add” 命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,而该对象的ID被记录在暂存区的文件索引中。
  4. 当执行提交操作(git commit)时,暂存区的目录树写到版本库(对象库)中,master 分支会做相应的更新。即 master 指向的目录树就是提交时暂存区的目录树。
  5. 当执行 “git reset HEAD” 命令时,暂存区的目录树会被重写,被 master 分支指向的目录树所替换,但是工作区不受影响。
  6. 当执行 “git rm –cached ” 命令时,会直接从暂存区删除文件,工作区则不做出改变
  7. 当执行 “git checkout .” 或者 “git checkout – ” 命令时,会用暂存区全部或指定的文件替换工作区的文件。这个操作很危险,会清除工作区中未添加到暂存区的改动。
  8. 当执行 “git checkout HEAD .” 或者 “git checkout HEAD ” 命令时,会用 HEAD 指向的 master 分支中的全部或者部分文件替换暂存区和以及工作区中的文件。这个命令也是极具危险性的,因为不但会清除工作区中未提交的改动,也会清除暂存区中未提交的改动。

创建仓库

  1. 你可以使用一个已经存在的目录作为Git仓库
    使用我们指定目录作为Git仓库。初始化后,会在 newrepo 目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中
git init newrepo
  1. 使用 git clone 从现有 Git 仓库中拷贝项目
git clone <repo>

如果要克隆到指定目录

git clone <repo> <directory>

参数说明:

  • repo:Git 仓库。
  • directory:本地目录。

git的基本操作

Git 的工作就是创建和保存你的项目的快照及与之后的快照进行对比。下面将对有关创建与提交项目的快照的命令作介绍。

git add

$ touch README$ touch hello.php$ lsREADME      hello.php$ git status -s?? README?? hello.php

注:git status 命令用于查看项目的当前状态。
接下来我们执行 git add 命令来添加文件:

$ git add README hello.php 

如果一次添加所有文件,我们可以直接使用 git add .

$ git add .

现在我们再执行 git status,就可以看到这两个文件已经加上去了:

$ git status -sA  READMEA  hello.php

现在我们修改 README 文件:

$ sudo nano README Git 测试$ git status -sAM READMEA  hello.php$ git add .$ git status -sA  READMEA  hello.php

git status

git status 以查看在你上次提交之后是否有修改。
我演示该命令的时候加了 -s 参数,以获得简短的结果输出。如果没加该参数会详细输出内容:

$ git statusOn branch masterInitial commitChanges to be committed:  (use "git rm --cached <file>..." to unstage)    new file:   README    new file:   hello.php

git diff

执行 git diff 来查看执行 git status 的结果的详细信息。
git diff 命令显示已写入缓存与已修改但尚未写入缓存的改动的区别。

  • 尚未缓存的改动:git diff
  • 查看已缓存的改动: git diff –cached
  • 查看已缓存的与未缓存的所有改动:git diff HEAD
  • 显示摘要而非整个 diff:git diff –stat

在 hello.php 文件中输入以下内容:

<?phpecho 'Hello world';?>
$ git status -sA  READMEAM hello.php$ git diffdiff --git a/hello.php b/hello.phpindex e69de29..69b5711 100644--- a/hello.php+++ b/hello.php@@ -0,0 +1,3 @@+<?php+echo 'Hello world';+?>

git status 显示你上次提交更新后的更改或者写入缓存的改动, 而 git diff 一行一行地显示这些改动具体是什么。
接下来我们来查看下 git diff –cached 的执行效果:

$ git add hello.php $ git status -sA  READMEA  hello.php$ git diff --cacheddiff --git a/README b/READMEnew file mode 100644index 0000000..8f87495--- /dev/null+++ b/README@@ -0,0 +1 @@+# Runoob Git 测试diff --git a/hello.php b/hello.phpnew file mode 100644index 0000000..69b5711--- /dev/null+++ b/hello.php@@ -0,0 +1,3 @@+<?php+echo 'Hello world';+?>

git commit

使用 git add 命令将想要快照的内容写入缓存区, 而执行 git commit 将缓存区内容添加到仓库中。
Git 为你的每一个提交都记录你的名字与电子邮箱地址,所以第一步需要配置用户名和邮箱地址。

$ git config --global user.name 'test'$ git config --global user.email test@augmentum.com

接下来我们写入缓存,并提交对 hello.php 的所有改动。在首个例子中,我们使用 -m 选项以在命令行中提供提交注释。

$ git status -sA  READMEA  hello.php$ git commit -m '第一次版本提交'[master (root-commit) d32cf1f] 第一次版本提交 2 files changed, 4 insertions(+) create mode 100644 README create mode 100644 hello.php

现在我们已经记录了快照。如果我们再执行 git status:

$ git status# On branch masternothing to commit (working directory clean)

如果你觉得 git add 提交缓存的流程太过繁琐,Git 也允许你用 -a 选项跳过这一步。命令格式如下:

git commit -a

我们先修改 hello.php 文件为以下内容:

<?phpecho 'Hello world';echo 'Hello world';?>

再执行以下命令:

git commit -am '修改 hello.php 文件'[master 71ee2cb] 修改 hello.php 文件 1 file changed, 1 insertion(+)

git reset HEAD

git reset HEAD 命令用于取消已缓存的内容。
我们先改动文件 README 文件,内容如下:

Git 测试
Hello world

hello.php 文件修改为:

<?phpecho 'Hello world';echo 'Hello world';echo 'Hello world';?>

现在两个文件修改后,首先都提交到缓存区:

$ git status -s M README M hello.php$ git add .$ git status -sM  READMEM  hello.pp

我们现在要取消其中一个的缓存,操作如下:

$ git reset HEAD -- hello.php Unstaged changes after reset:M   hello.php$ git status -sM  README M hello.php

现在你执行 git commit,只会将 README 文件的改动提交,而 hello.php 是没有的.

$ git commit -m '修改'[master f50cfda] 修改 1 file changed, 1 insertion(+)$ git status -s M hello.php

可以看到 hello.php 文件的修改并为提交。
这时我们可以使用以下命令将 hello.php 的修改提交:

$ git commit -am '修改 hello.php 文件'[master 760f74d] 修改 hello.php 文件 1 file changed, 1 insertion(+)$ git statusOn branch masternothing to commit, working directory clean

执行 git reset HEAD 以取消之前 git add 添加,不希望包含在下一提交快照中的缓存

git rm

git rm 会将条目从缓存区中移除。这与 git reset HEAD 将条目取消缓存是有区别的。 “取消缓存”的意思就是将缓存区恢复为我们做出修改之前的样子。
默认情况下,git rm file 会将文件从缓存区和你的硬盘中(工作目录)删除。
如果你要在工作目录中留着该文件,可以使用 git rm –cached:
如我们删除 hello.php文件:

$ git rm hello.php rm 'hello.php'$ lsREADME

不从工作区中删除文件:

$ git rm --cached README rm 'README'$ lsREADME

在下一节开始之前先将README添加回来。

$ git add README$ git commit -m '删除hello.php' 

git的分支管理

创建分支命令:

创建分支命令:

git branch (branchname)

切换分支命令:

git checkout (branchname)

没有参数会列出分支:

$ git branch* master

当你执行 git init 的时候,缺省情况下 Git 就会为你创建”master”分支。
如果我们要手动创建一个分支,并切换过去。执行 git branch (branchname) 即可

$ git branch testing$ git branch* master  testing

现在我们可以看到,有了一个新分支 testing。
当以此方式在上次提交更新之后创建了新分支,如果后来又有更新提交, 然后又切换到了”testing”分支,Git 将还原你的工作目录到你创建分支时候的样子
接下来将演示如何切换分支,我们用 git checkout (branch) 切换到我们要修改的分支。

$ lsREADME$ echo 'this is a test.txt' > test.txt$ git add .$ git commit -m 'add test.txt'[master 048598f] add test.txt[master cf2f49a] add test.txt 1 file changed, 1 insertion(+), 1 deletion(-) create mode 100644 test.txt$ lsREADME      test.txt$ git checkout testingSwitched to branch 'testing'$ lsREADME

当我们切换到”testing”分支的时候,我们添加的新文件test.txt被移除了, 切换回”master”分支的时候,它又重新出现了。

$ git checkout masterSwitched to branch 'master'$ lsREADME      test.txt

我们也可以使用 git checkout -b (branchname) 命令来创建新分支并立即切换到该分支下,从而在该分支中操作

$ git checkout -b newtestSwitched to a new branch 'newtest'$ git rm test.txt rm 'test.txt'$ lsREADME$ git commit -am 'removed test.txt'[newtest 556f0a0] removed test.txt 1 file changed, 1 deletion(-) delete mode 100644 test.txt$ git checkout masterSwitched to branch 'master'$ lsREADME      test.txt

我们创建了一个分支,在该分支的上下文中移除了一些文件,然后切换回我们的主分支,那些文件又回来了。
使用分支将工作切分开来,从而让我们能够在不同上下文中做事,并来回切换。

删除分支

删除分支命令:

git branch -d (branchname)

例如我们要删除”testing”分支:

$ git branch* master  testing  newtest$ git branch -d testingDeleted branch testing (was 85fc7e7).$ git branch* master  newtest

分支合并

一旦某分支有了独立内容,你终究会希望将它合并回到你的主分支。 你可以使用以下命令将任何分支合并到当前分支中去:

git merge
$ git branch* master  newtest$ lsREADME      test.txt$ git merge newtestUpdating 2e082b7..556f0a0Fast-forward test.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 test.txt$ lsREADME

以上实例中我们将 newtest 分支合并到主分支去,test.txt 文件被删除。

合并冲突

合并并不仅仅是简单的文件添加、移除的操作,Git 也会合并修改。

$ git branch* master  newtest$ cat READMEGit 测试Hello world

首先,我们创建一个叫做”change_site”的分支,切换过去,我们将内容改为 this is change_site 。

$ git checkout -b change_siteSwitched to a new branch 'change_site'$ sudo nano  READMEthis is change_site $ git commit -am 'changed the site'[change_site d7e7346] changed the site 1 file changed, 1 insertion(+), 1 deletion(-)

将修改的内容提交到 “change_site” 分支中。 现在,假如切换回 “master” 分支我们可以看内容恢复到我们修改前的,我们再次修改README.md文件。

$ git checkout masterSwitched to branch 'master'$ cat READMEGit 测试Hello world$ sudo nano READMEGit 测试Hello worldHello world$ git diffdiff --git a/README b/READMEindex 1e84f3e..713114f 100644--- a/README.md+++ b/README.md@@ -1,3 +1,4 @@ add readme Git 测试 Hello world+Hello world$ git commit -am '新增加一行'[master 14b4dca] 新增加一行 1 file changed, 1 insertion(+)

现在这些改变已经记录到我的 “master” 分支了。接下来我们将 “change_site” 分支合并过来

$ git merge change_siteAuto-merging READMECONFLICT (content): Merge conflict in READMEAutomatic merge failed; fix conflicts and then commit the result.$ cat README <<<<<<< HEADGit 测试Hello worldHello world=======this is change_site>>>>>>> change_site

我们将前一个分支合并到 “master” 分支,一个合并冲突就出现了,接下来我们需要手动去修改它。

$ sudo nano README $ cat README  Git 测试Hello worldHello world$ git diffdiff --cc READMEindex f84c2a4,bccb7c2..0000000--- a/README+++ b/README

在 Git 中,我们可以用 git add 要告诉 Git 文件冲突已经解决

$ git status -sUU README$ git add .$ git commit[master 88afe0e] Merge branch 'change_site'

现在我们成功解决了合并中的冲突,并提交了结果。

Git 查看提交历史

在使用 Git 提交了若干更新之后,又或者克隆了某个项目,想回顾下提交历史,我们可以使用 git log 命令查看

$ git logcommit e2460552429bbc0762f69e859088d30e16b472caMerge: bcf46a4 feb2543Author: sonya.guo <test@augmentum.com>Date:   Wed Jul 13 14:54:22 2016 +0800    Merge branch 'change_site'    Conflicts:        READMEcommit bcf46a4e4002b6b45367608dd48bd30ffd6b0f2dAuthor: sonya.guo <test@augmentum.com>Date:   Wed Jul 13 14:46:53 2016 +0800    新增加一行commit feb254343356352e52783364c6f572a415635338Author: sonya.guo <test@augmentum.com>Date:   Wed Jul 13 14:40:24 2016 +0800    changed the sitecommit 06456a5c3deb496b459301e0ef62ae13c69ac602

我们可以用 –oneline 选项来查看历史记录的简洁的版本。

$ git log --onelinee246055 Merge branch 'change_site'bcf46a4 新增加一行feb2543 changed the site06456a5 removed test.txtcf2f49a add test.txt4b209c4 重命名6ee6734 修改 hello.php 文件1033b80 修改cc18d45 修改 hello.php 文件6ea167d 第一次版本提交bf5a2e9 update READMEfd58d0a add test.txt6f62a64 add README

Git远程仓库

查看当前的远程库

git remote
$ git remoteorigin

执行时加上 -v 参数,你还可以看到每个别名的实际链接地址。

提取远程仓库

Git 有两个命令用来提取远程仓库的更新
1. 从远程仓库下载新分支与数据:

git fetch

该命令执行完后需要执行git merge 远程分支到你所在的分支。
2. 从远端仓库提取数据并尝试合并到当前分支:

git pull

git pull的命令等同于在执行 git fetch 之后紧接着执行 git merge 远程分支到你所在的任意分支。
假设你配置好了一个远程仓库,并且你想要提取更新的数据,你可以首先执行 git fetch [alias] 告诉 Git 去获取它有你没有的数据,然后你可以执行 git merge [alias]/[branch] 以将服务器上的任何更新(假设有人这时候推送到服务器了)合并到你的当前分支。
接下来我们在 Git 上点击”README.txt” 并在线修改它。之后我们在本地更新修改。

$ git fetch originWarning: Permanently added the RSA host key for IP address '192.30.252.128' to the list of known hosts.remote: Counting objects: 3, done.remote: Compressing objects: 100% (2/2), done.remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0Unpacking objects: 100% (3/3), done.From github.com:tianqixin/w3cschool.cc   7d2081c..f5f3dd5  master     -> origin/master

以上信息”7d2081c..f5f3dd5 master -> origin/master” 说明 master 分支已被更新,我们可以使用以下命令将更新同步到本地:

$ git merge origin/masterUpdating 7d2081c..f5f3dd5Fast-forward "w3cschool\350\217\234\351\270\237\346\225\231\347\250\213\346\265\213\350\257\225.txt" | 1 + 1 file changed, 1 insertion(+)

推送到远程仓库

推送你的新分支与数据到某个远端仓库命令:

git push [alias] [branch]

以上命令将你的 [branch] 分支推送成为 [alias] 远程仓库上的 [branch] 分支,实例如下

$ git merge origin/masterUpdating 7d2081c..f5f3dd5Fast-forward "w3cschool\350\217\234\351\270\237\346\225\231\347\250\213\346\265\213\350\257\225.txt" | 1 + 1 file changed, 1 insertion(+)bogon:w3cschoolcc tianqixin$ vim w3cschool菜鸟教程测试.txt bogon:w3cschoolcc tianqixin$ git push origin masterEverything up-to-date

删除远程仓库

删除远程仓库你可以使用命令:

git remote rm [别名]
$ git remote -vorigin  git@github.com:tianqixin/w3cschool.cc.git (fetch)origin  git@github.com:tianqixin/w3cschool.cc.git (push)$ git remote add origin2 git@github.com:tianqixin/w3cschool.cc.git$ git remote -vorigin  git@github.com:tianqixin/w3cschool.cc.git (fetch)origin  git@github.com:tianqixin/w3cschool.cc.git (push)origin2 git@github.com:tianqixin/w3cschool.cc.git (fetch)origin2 git@github.com:tianqixin/w3cschool.cc.git (push)$ git remote rm origin2$ git remote -vorigin  git@github.com:tianqixin/w3cschool.cc.git (fetch)origin  git@github.com:tianqixin/w3cschool.cc.git (push)

番外篇

git merge 和git rebase

Git merge是用来合并两个分支的。
git merge b将b分支合并到当前分支
同样 git rebase b,也是把 b分支合并到当前分支
他们的 原理 如下:
假设你现在基于远程分支”origin”,创建一个叫”mywork”的分支。
$ git checkout -b mywork origin
假设远程分支”origin”已经有了2个提交,如图

cmd-markdown-logo

现在我们在这个分支做一些修改,然后生成两个提交(commit).
但是与此同时,有些人也在”origin”分支上做了一些修改并且做了提交了. 这就意味着”origin”和”mywork”这两个分支各自”前进”了,它们之间”分叉”了。

cmd-markdown-logo

在这里,你可以用”pull”命令把”origin”分支上的修改拉下来并且和你的修改合并; 结果看起来就像一个新的”合并的提交”(merge commit):

cmd-markdown-logo

但是,如果你想让”mywork”分支历史看起来像没有经过任何合并一样,你也许可以用 git rebase:

$ git checkout mywork$ git rebase origin

这些命令会把你的”mywork”分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到”.git/rebase”目录中),然后把”mywork”分支更新 为最新的”origin”分支,最后把保存的这些补丁应用到”mywork”分支上。

cmd-markdown-logo

当’mywork’分支更新之后,它会指向这些新创建的提交(commit),而那些老的提交会被丢弃。 如果运行垃圾收集命令(pruning garbage collection), 这些被丢弃的提交就会删除.

cmd-markdown-logo


Git Hooks

什么是Git Hooks?

如同其他许多的版本控制系统一样,Git也具有在特定事件发生之前或之后执行特定脚本代码功能(从概念上类比,就与监听事件、触发器之类的东西类似)。Git Hooks就是那些在Git执行特定事件(如commit、push、receive等)后触发运行的脚本。
按照Git Hooks脚本所在的位置可以分为两类:

  • 本地Hooks,触发事件如commit、merge等。
  • 服务端Hooks,触发事件如receive等。

Git Hooks能做什么?

Git Hooks是定制化的脚本程序,所以它实现的功能与相应的git动作相关;在实际工作中,Git Hooks还是相对比较万能的。下面仅举几个简单的例子:

  • pre-commit: 检查每次的commit message是否有拼写错误,或是否符合某种规范。
  • pre-receive: 统一上传到远程库的代码的编码。
  • post-receive: 每当有新的提交的时候就通知项目成员(可以使用Email或SMS等方式)。
  • post-receive: 把代码推送到生产环境。

Git Hooks是如何工作的?

每一个Git repo下都包含有.git/hoooks这个目录(没错,本地和远程都是这样),这里面就是放置Hooks的地方。你可以在这个目录下自由定制Hooks的功能,当触发一些Git行为时,相应地Hooks将被执行。

对于任何Git仓库来说钩子都是本地的,而且它不会随着git clone一起复制到新的仓库。而且,因为钩子是本地的,任何能接触得到仓库的人都可以修改。

在开发团队中维护钩子是比较复杂的,因为.git/hooks目录不随你的项目一起拷贝,也不受版本控制影响。一个简单的解决办法是把你的钩子存在项目的实际目录中(在.git外)。这样你就可以像其他文件一样进行版本控制。为了安装钩子,你可以在.git/hooks中创建一个符号链接,或者简单地在更新后把它们复制到.git/hooks目录下。

这里是一个Git Hooks列表:

  • applypatch-msg
  • pre-applypatch
  • post-applypatch
  • pre-commit
  • prepare-commit-msg
  • commit-msg
  • post-commit
  • pre-rebase
  • post-checkout
  • post-merge
  • pre-receive
  • update
  • post-receive
  • post-update
  • pre-auto-gc

如何开始使用Git Hooks?

  1. 写脚本。
    内置的脚本大多是shell和Perl语言的,但你可以使用任何脚本语言,只要它们最后能编译到可执行文件。每次脚本中的#!/bin/sh定义了你的文件将被如何解释。比如,使用其他语言时你只需要将path改为你的解释器的路径。
    比如说,你可以在prepare-commit-msg中写一个可执行的Python脚本。
#!/usr/bin/env pythonimport sys, oscommit_msg_filepath = sys.argv[1]with open(commit_msg_filepath, 'w') as f:    f.write("# Please include a useful commit message!")    /*注意第一行改成了Python解释器的路径。*/
  1. 关于这些脚本文件的命名,以列表中的名字直接命名,就会把该脚本绑定到特定的Git行为上.
0 0
原创粉丝点击