声明:这个只是个人的学习笔记,仅针对本人的实际情况,如果有什么不喜,请评论。
说明: 下面命令里面有个 $ 符号,这个只是模拟terminal里面的样子,可以忽略。
基础看完,你应该能够配置并初始化一个仓库(repository)、开始或停止跟踪(track)文件、暂存(stage)或提交(commit)更改。 本章也将向你演示如何配置 Git 来忽略指定的文件和文 件模式、如何迅速而简单地撤销错误操作、如何浏览你的项目的历史版本以及不同提交(commits)间的差异、 如何向你的远程仓库推送(push)以及如何从你的远程仓库拉取(pull)文件。
获取 Git 仓库
有2种方式你可以获取Git仓库,一种是将现有的项目导入到Git中,第二种就是从服务器上克隆一个Git仓库下来。
在现有目录中初始化仓库
进入你现有项目的目录里面,然后输入 git init。
完成后你会得到一个 .git的隐藏子目录
这里面包含了Git仓库的重要信息,仅仅是初始化还是不够的,我们需要把我们项目的文件添加(add)到本地暂存的地方再提交(commit)到本地的Git(Repository)上面去。这样就可以真正的初始化我们的Git仓库了,对我们需要提交的文件进行版本控制。
$ git add *.c $ git add LICENSE $ git commit -m 'initial project version'
克隆现有的Git仓库
这里要执行的是 git clone,如果你对其它的 VCS 系统(比如说Subversion)很熟悉,请留心一下你所使用的命令 是"clone"而不是"checkout"。
克隆下来的基本是每个文件的所有版本信息。
克隆仓库的命令格式是 git clone [url] 。
比如,要克隆 Git 的可链接库 libgit2,可以用下面的命令:
$ git clone https://github.com/libgit2/libgit2
这会在当前目录下创建一个名为 “libgit2” 的目录,并在这个目录下初始化一个 .git 文件夹,从远程仓库拉取下所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝。
如果想自定义本地仓库的名字 可以 git clone [url] name
记录每次更新到仓库
这就是文件的生命周期。
这里讲解下这对之后理解文件的各种操作更加容易。
Untracked :这个是没被跟踪的文件。出现这种情况大概就是现有项目新建的文件,总的理解就是远程的Git仓库里面还没有这个文件的版本信息。
Staged:本地的暂存。其实用惯了svn啥的第一次用git还是不习惯的,我改好了文件直接上传到远程版本控制服务器上不就好了,为什么要先add(添加修改)到暂存再commit(提交)到本地仓库,再push到远程,多此一举。这个使用(一)里面已经说过了,这里就不赘述了。
Unmodified: 我新建的文件(状态:Untracked),我对它进行本地的暂存(状态:Staged),再将它push到远程后(状态:Unmodified),为什么会变成Unmodified,因为本地的版本和远程上一致的所以就上未修改的状态了(Unmodified)。
Modified: 对版本一致的文件进行修改后,系统会检测到,然后将文件的状态改变成Modified状态,我们同样要对它进行add到本地暂存再commit到本地仓库,然后再push到远程。
还有remove(删除文件)这块基本流程和修改文件的流程一样。看后面的解释应该就可以理解,这里先讲个大概。
检查当前文件状态
再我们不知道现在本地仓库是什么状态的时候,我们可以在.git所在的目录下 cmd 或者terminal 或者 安装git带的控制台输入 git status 查看状态。
$ git status On branch master nothing to commit, working directory clean
解释下上面 :在主(master)分支上, 没有文件可以提交,工作目录贼鸡儿干净。
分支这块是巨头,下一篇再说。
现在,让我们在项目下创建一个新的 README 文件。 如果之前并不存在这个文件,使用 git status 命令,你 将看到一个新的未跟踪文件:
$ echo 'My Project' > README $ git status On branch master Untracked files:
(use "git add <file>..." to include in what will be committed) README
nothing added to commit but untracked files present (use "git add" to track)
看到提示说我们有没有被追踪的文件,可以添加它。
跟踪新文件
那我们就添加它到本地的暂存。
使用命令 git add 开始跟踪一个文件。 所以,要跟踪 README 文件,运行:
$ git add README
$ git status On branch master Changes to be committed:
(use "git reset HEAD <file>..." to unstage) new file: README
它说一个文件被提交了,可以使用 git reset 把它从暂存的地方去除。
这个就是说,将暂存的地方修改成还没提交这个文件现在这个版本的时候的样子。
场景的话:我commit了一个我不想要提交的文件到了暂存的地方,但是我不想把它push到远程服务器上面去,然后我就可以用reset 把这个从暂存的地方剔除。
暂存已修改文件
我修改了一个被跟踪的文件,假设它的名字是 :CONTRIBUTING.md
然后我们查看 git status
$ git status On branch master Changes to be committed:
(use "git reset HEAD <file>..." to unstage) new file: README
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: CONTRIBUTING.md
文件CONTRIBUTING.md出现在Changes not staged for commit这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。 要暂存这次更新,需要运行 git add 命令。 这是个多功能命令:可以用它开 始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。 将这 个命令理解为“添加内容到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。 现在让我们运行git add将"CONTRIBUTING.md"放到暂存区,然后再看看git status的输出:
$ git add CONTRIBUTING.md $ git status On branch master Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README modified: CONTRIBUTING.md
现在两个文件都已暂存,下次提交时就会一并记录到仓库。 假设此时,你想要在 CONTRIBUTING.md 里再加条注释, 重新编辑存盘后,准备好提交。 不过且慢,再运行 git status 看看:
$ vim CONTRIBUTING.md $ git status On branch master Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README modified: CONTRIBUTING.md
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: CONTRIBUTING.md
怎么回事? 现在 CONTRIBUTING.md 文件同时出现在暂存区和非暂存区。 这怎么可能呢? 好吧,实际上 Git 只 不过暂存了你运行 git add 命令时的版本, 如果你现在提交,CONTRIBUTING.md 的版本是你最后一次运行git add 命令时的那个版本,而不是你运行 git commit 时,在工作目录中的当前版本。 所以,运行了 git add之后又作了修订的文件,需要重新运行git add把最新版本重新暂存起来:
$ git add CONTRIBUTING.md $ git status On branch master Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README modified: CONTRIBUTING.md
状态简览
$ git status -s M README MM Rakefile A lib/git.rb M lib/simplegit.rb ?? LICENSE.txt
上面有M很迷,??这个清楚点就是连git都不知道这个点状态那肯定是没有被追踪的文件,需要执行git add 操作。
A 的话那肯定是 被 add 过的文件,README 它的M 靠右边点,意思是修改了还没被存到暂存区。lib/simplegit.rb 它的M靠左边,意思是被修改了并且被添加到了暂存区。MM的意思就是之前修改的存了,然后又修改了。
忽略文件
忽略文件是挺重要的一块,因为我们有些时候是不把第三方库提交到Git上面去的,我们只需要添加过控制第三库版本的文件,不然过多的库文件会使仓库变的很大,这个目的就偏离了我们对自己的文件进行版本控制管理的理念。我们的仓库就控制我们自己最主要的文件,第三库的文件,我们提供它的版本库的信息,比如pom文件。每个人clone 或者pull 了远程的项目,他们添加了第三方库,或者修改了我们只需要更新个pom文件,具体的文件我们让库依赖系统来帮我们管理,如 maven。
我们可以创建一个名为 .gitignore的文件,列出要忽略的文件模式。 来看一个实际的例子:
$ cat .gitignore *.[oa] *~
第一行告诉 Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就设置好.gitignore 文件的习惯,以免将来误提交这类无用的文件。
文件 .gitignore 的格式规范如下:
• 所有空行或者以 # 开头的行都会被 Git 忽略。• 可以使用标准的 glob 模式匹配。
• 匹配模式可以以(/)开头防止递归。
• 匹配模式可以以(/)结尾指定目录。
• 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc] 匹配
任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(*) 表示匹配任意中间目录,比如`a/**/z` 可以匹配 a/z, a/b/z 或 `a/b/c/z`等。
TIP
GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表,你可以在https://github.com/github/gitignore 找到它.
查看已暂存和未暂存的修改
其实这个,个人感觉用命令git diff 也可以查看,但是用GUI的软件看比较实在点,有些花里胡哨的东西可能不好,但是查看代码文件的差异,还是要有这么个东西检查起来还是很方便的。
这里就不详细描述了,自己尝试下,会发现还是用其他插件舒服。
提交更新
$ git commit
这种方式会启动文本编辑器以便输入本次提交的说明。 (默认会启用 shell 的环境变量 $EDITOR 所指定的软件, 一般都是vim或emacs。当然也可以按照起步介绍的方式,使用git config --global core.editor命 令设定你喜欢的编辑软件。)
commit的时候会打开个文本需要你输入提交时候的备注信息,这个似乎是强制性的。
另外,你也可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行,
$ git commit -m "Story 182: Fix benchmarks for speed" [master 463dc4f] Story 182: Fix benchmarks for speed
2 files changed, 2 insertions(+) create mode 100644 README
跳过使用暂存区域
尽管使用暂存区域的方式可以精心准备要提交的细节,但有时候这么做略显繁琐。 Git 提供了一个跳过使用暂存区域的方式, 只要在提交的时候,给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过git add步骤
移除文件
要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。可以用git rm命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。
如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 “Changes not staged for commit” 部分(也就是 未暂存清单)看到:
$ rm PROJECTS.md $ git status On branch master Your branch is up-to-date with 'origin/master'. Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
deleted: PROJECTS.md no changes added to commit (use "git add" and/or "git commit -a")
然后再运行git rm记录此次移除文件的操作:
$ git rm PROJECTS.md rm 'PROJECTS.md' $ git status On branch master Changes to be committed:
(use "git reset HEAD <file>..." to unstage) deleted: PROJECTS.md
下一次提交时,该文件就不再纳入版本管理了。 如果删除之前修改过并且已经放到暂存区域的话,则必须要用 强制删除选项 -f(译注:即 force 的首字母)。 这是一种安全特性,用于防止误删还没有添加到快照的数据, 这样的数据不能被 Git 恢复。
另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。 换句话说,你想让文件保留在磁盘,但是并不想让 Git 继续跟踪。 当你忘记添加 .gitignore 文件,不小 心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时,这一做法尤其有用。 为达到这一目 的,使用 --cached 选项:
$ git rm --cached README
移动文件
$ git mv file_from file_to
这个可以看作平时在shell上使用的 mv 可以改名同时也可以转移文件。
查看提交历史
git log
撤销操作
有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选项的提交命令尝试重新提交:
$ git commit --amend
$ git commit -m 'initial commit' $ git add forgotten_file $ git commit --amend
最终你只会有一个提交 - 第二次提交将代替第一次提交的结果。
取消暂存的文件
接下来的两个小节演示如何操作暂存区域与工作目录中已修改的文件。 这些命令在修改文件状态的同时,也会 提示如何撤消操作。 例如,你已经修改了两个文件并且想要将它们作为两次独立的修改提交,但是却意外地输 入了 git add * 暂存了它们两个。 如何只取消暂存两个中的一个呢? git status 命令提示了你:
$ git add * $ git status On branch master Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README modified: CONTRIBUTING.md
使用 git reset HEAD filename 来取消暂存。
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: CONTRIBUTING.md
如果想要丢弃你之前的修改,那么可以重新 checkout一份覆盖你修改的,这样你之前的修改就被丢弃了。
远程仓库的使用
如果想查看你已经配置的远程仓库服务器,可以运行 git remote 命令。 它会列出你指定的每一个远程服务器的简写。 如果你已经克隆了自己的仓库,那么至少应该能看到 origin - 这是 Git 给你克隆的仓库服务器的默认名字:
$ git clone https://github.com/schacon/ticgit Cloning into 'ticgit'... remote: Reusing existing pack: 1857, done. remote: Total 1857 (delta 0), reused 0 (delta 0) Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done. Resolving deltas: 100% (772/772), done.
Checking connectivity... done. $ cd ticgit $ git remote origin
git remote -v
如果你的远程仓库不止一个,该命令会把所有的全部列出了
添加远程仓库
git remote add <shortname> <url>添加一个新的远程Git仓库
从远程仓库中抓取与拉取
$ git fetch [remote-name]
这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支 的引用,可以随时合并或查看。
如果你使用 clone 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 “origin” 为简写。 所 以,git fetch origin会抓取克隆(或上一次抓取)后新推送的所有工作。必须注意git fetch命令会将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工 作。
如果你有一个分支设置为跟踪一个远程分支(阅读下一节与Git分支了解更多信息),可以使用git pull命 令来自动的抓取然后合并远程分支到当前分支。 这对你来说可能是一个更简单或更舒服的工作流程;默认情况下,git clone命令会自动设置本地master分支跟踪克隆的远程仓库的master分支(或不管是什么名字的默认分支)。运行git pull通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。
推送到远程仓库
当你想分享你的项目时,必须将其推送到上游。 这个命令很简单:git push [remote-name] [branch- name]。 当你想要将 master 分支推送到 origin 服务器时(再次说明,克隆时通常会自动帮你设置好那两个 名字),那么运行这个命令就可以将你所做的备份到服务器:
$ git push origin master
只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。 当你和其他人在同一时 间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。
查看远程仓库
git remote show [remote-name]