Git基础

2.1 获取Git仓库

建立Git仓库的方法主要有两种。第一种是把现有的项目或者目录导入到Git中,第二种是从服务器上克隆现有的Git仓库。

2.1.1 从现有目录中初始化Git仓库

要想在Git种对现有的项目进行跟踪管理,只需要进入项目目录并輸入

$ git init

这会创建一个名为.git的子目录。这个子目录包含了构成Git仓库骨架的所有必须文件。但此时Git尚未跟踪项目中的任何文件。

如果你打算对手头现有文件(非空目录)进行版本控制,那么就应该开始跟踪这些文件并进行初次提交。对需要跟踪的文件执行几次git add命令,然后輸入git commit命令即可:

$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'

现在,你的Git仓库已经包含了这些被跟踪的文件并进行了初次提交。

2.1.2 克隆现有仓库

如果你想获取现有仓库的一份副本,可以使用git clone命令。Git对服务器仓库的几乎所有数据进行完整复制,而不是只复制当前工作目录。git clone默认会从服务器上把整个项目历史中的每个文件的所有历史版本都拉下来。

克隆仓库需要使用git clone [url] 命令。例如,要克隆某一个GitHub上的库:

$ git clone https://github.com/libgit2/libgit2.git

这会创建一个名为libgit2的新目录,并在其中初始化.git目录,然后将远程仓库中的所有数据拉取到本地并检出最新版本的可用副本。

如果你想将项目克隆到其他名字的目录中,可以把目录名作为命令行选项传入:

$ git clone https://github.com/libgit2/libgit2.git mylibgit

这一条命令与上一条命令功能相同,只是目标目录的名字变成了mylibgit。

2.2 在Git仓库中记录变更

你现在拥有了一个真正的Git仓库并检出了项目文件的可用副本。下一步就是做出一些更改,当项目达到某个需要记录的状态时向仓库提交这些变更的快照。

工作目录下的每一个文件都处于两种状态之一:已跟踪(tracked)或未跟踪(untracked)。已跟踪的文件是指上一次快照中包含的文件。这些文件又可以分为未修改、已修改或已暂存三种状态。而未跟踪的文件则是工作目录中出去已跟踪文件之外的所有文件,也就是既不在上一次快照中,也不在暂存区的文件中。

当你刚完成仓库克隆时,所有文件的状态都是已跟踪且未修改的,因为你刚把它们检出,而且没有做出任何的修改。

如果修改了文件,它们在Git中的状态就会变成已修改,这意味着自从上次提交以来文件已经发生了变化,需要把这些已修改的文件添加到暂存区,提交所有已暂存的变更,随后重复这个过程。

文件状态的生命周期:

 

 

2.2.1 查看当前文件状态

检查文件所处状态的主要工具是 git status 命令。该命令还会显示当前所处的分支,告诉你现在所处的本地分支与服务器上对应的分支是否出现了偏离。

git status输出信息中,Untracked files (未跟踪的文件)条目下,会显示新的处于未跟踪状态的文件名列表。未跟踪的文件就是Git在上一次快照(提交)中没有发现的文件。Git并不会主动的把这些文件包含到下一次提交的文件范围中,除非你明确的告诉Git你需要跟踪这些文件。

2.2.2 跟踪新文件

可以用git add 命令让Git跟踪新文件,执行下面命令来跟踪新的README文件。

$ git add README

然后,你再次执行git statues命令时,就可以看到该文件已处于跟踪状态了,并被添加到暂存区等待提交。在git status的输出信息中,”Changes to be commited" (等待提交的更改)标题下列出的就是已暂存的文件。如果现在提交,那么之前执行git add时的文件版本就会被添加到历史快照中。

2.2.3 暂存已修改的文件

如果你修改了之前已经被Git跟踪的文件,再次执行git status命令,就会看到该文件会出现在“Changes not staged for commit" (已更改但未添加到暂存区)的区域中,这表示处于跟踪状态的文件在工作目录下已被修改,但尚未被添加到暂存区。要想暂存这些文件,需要执行git add命令。git add是一个多功能命令,既可以用来跟踪新文件,也剋以用来暂存文件,它还可以做一些其他的事情,比如把存在合并冲突的文件标记已解决。所以,把git add命令看成”添加内容到下一次提交中“更有利于理解该命令。

如果你执行git add命令,将文件添加到暂存区后,再次对该文件进行修改。这时,你会发现git status的输出信息中,该文件同时出现在已暂存和未暂存的列表中。

因为,在暂存一个文件时,Git保存的是你执行git add时文件的样子。如果你现在执行git commit命令提交,则包含在这次提交中的文件是你上次执行git add命令时的版本,而不是现在工作目录中该文件的当前版本。所以,执行了git add之后有对添加到暂存区的文件做了修改,需要再完成一次git add将文件的最新版本添加到暂存区。

 

2.2.4 显示更简介的状态信息

虽然给git status 命令输出的信息很全面也很冗长。对此,Git也提供了一个显示状态的命令行选项,即git status -s 或者 git status --short。

显示信息中,未被跟踪的文件旁边会有个??标记,已暂存的新文件会有A标记,而已修改的文件则会有个M标记,等等。

 

2.2.5 忽略文件

如果你不希望某些文件被Git自动添加,甚至不想这些文件显示在未跟踪的文件列表下面,一般这些文件是自动生成的文件(比如日志文件)或者是由构建系统创建的文件等。在这种情况下,你可以创建名为.gitignore的文件,在其中列出待匹配文件的模式。

可以写入gitignore文件中的匹配模式的规则如下:

  • 空行或者以#开始的行会被忽略
  • 支持标准的glob模式
  • 以斜杠(/)开头的模式可用于禁止递归匹配
  • 以斜杠(/)结尾的模式表示目录
  • 以感叹号(!)开始的模式表示取反

2.2.6 查看已暂存和为暂存的变更

可以用git diff命令,可以解决两个问题:哪些变更还没有被暂存?哪些已暂存的变更正待提交?该命令输出的是补丁(patch)。

注意:git diff本身并不会显示出自从上一次提交以来所有的变更,而只会显示出还没有进入暂存区的那些变更。如果你已经把所有变更添加到了暂存区,git diff不会有任何输出。

 

2.2.7 提交变更

请记得所有未暂存的变更不会进入到提交的内容中,这包括任何在编辑之后没有执行git add命令添加到暂存区的新建的或修改过的文件。而提交过后,这些文件的状态依然不会发生变化,仍然是已修改的状态。

最简单的提交方式就是git commit命令:

$ git commit

执行这条命令后,就会打开你所选择的文本编辑器。默认会采用shell的环境变量所指定的文本编辑器。你可以輸入自己的提交信息,然后完成提交。

当然,你也可以直接在命令行键入提交信息,需要给git commit命令加上-m选项:

$ git commit -m "Story 182: Fix benchmarks for speed"

完成提交后,命令输出中包含了和该提交本身相关的一些信息:提交到哪个分支(master)、提交的SHA-1校验和是多少、改动了多少个文件以及源文件新增和删除了多少行的统计信息。

注意:提交是记录的是暂存区中的快照,任何未暂存的内容仍然保持着已修改状态。你可以再次提交这些内容,将其纳入到版本历史记录中。

 

2.2.8 跳过暂存区

如果你想跳过暂存区直接提交,Git为你提供了更快捷的途径。git commit命令传入-a选项,这样就能让Git自动把已跟踪的所有文件添加到暂存区,然后再提交,这样你就不用再执行git add了。

 

2.2.9 移除文件

要从GIt中移除某个文件,你需要先把它从已跟踪文件列表中移除,(确切的说,是从暂存区中移除),然后再提交。git rm会帮你完成这些操作,另外该命令还会把文件从工作区目录中移除,这样下一次你就不会在未跟踪文件列表中看到这些文件了。

如果你只是简单地把文件从你的工作目录移除,而没有使用git rm,那么在执行git status时会看到文件出现在”Changes not stages for commit“ 区域(也就是护送未暂存区域)。如果你执行git rm, Git才会把文件的移除状态记录到暂存区。下一次提交的时候,这个文件就不存在了,也不会再被Git跟踪管理。

如果你更改了某个文件,并已经把它加入到了索引当中(已暂存),要想让Git移除它就必须使用-f选项强制删除。这是为了防止没有被记录到快照中的数据被意外移除而设立的安全特性。因为这样的数据被意外移除后无法由Git恢复。

另一中情况就是把文件保留在工作目录,但从暂存区中移除该文件。换句话说,就是你或许想将文件留在磁盘上,但不想让Git对其进行跟踪管理。例如,如果你忘了向.gitignore文件中添加相应的规则,不小心把一个很大的日志文件或者一些编译生成的.a文件添加进来,上述做法尤其有用。只需要使用--cached选项即可:

$ git rm --cached [filename]

你可以将文件、目录和文件的glob模式传递给git rm命令。这意味着你可以像下面这样:

$ git rm log/\*.log

注意:在*前面的反斜杠(\)是必须的,因为shell和Git先后都要处理文件名扩展。上述命令会移除log目录中所有扩展名为.log的文件。或者,也可以像下面这样:

$ git rm \*~

这条命令会移除所有以~结尾的文件。

 

2.2.10 移动文件

Git不会显式跟踪文件的移动,如果你在Git中重命名了文件,仓库的元数据并不会记录这次重命名操作。不过Git会检测到文件的移动操作。Git中的可以执行下面的命令重命名文件:

$ git mv file_from file_to

例如:你执行了:

$ git mv README.md README

其实相当于你执行了下面的三条指令:

$ mv README.md README
$ git rm README.md
$ git add README

不管你是用Git的mv命令,还是直接给文件改名,Git都能判断出这是重命名操作。唯一的区别是git mv只需要键入一条命令而不是三条命令,这样会比较方便。当然,你可以用任何的你喜欢的工具或方法来重命名文件,然后在提交之前再执行Git的add和rm命令。

 

2.3 查看提交历史

在完成几次提交,或克隆一个已有提交历史的仓库之后,你可能想要看看历史记录。用git log命令来实现,这是最基础却又最强大的一条命令。

默认不加参数的情况下,git log会按照时间顺序列出仓库中的所有提交。其中最新的提交显示在最前面。和每个提交一同列出的还有他的SHA-1校验和、作者姓名和邮箱、提交日期以及提交信息。

git log由很多不同的选项,可以直观地展示出所需地内容。

  -p,显示出每次提交所引入地差异,后面可以加上-2参数,只输出最近的两次提交。

  --stat选项来查看每个提交地简要统计信息。

  --pretty选项可以更改日志输出地默认格式;,还有format选项,允许指定自己的输出格式;

  如:

$ git log --pretty=online
$ git log --pretty=format: "%h - %an, %ar : %s"

 

2.4 撤销操作

撤销操作是不可逆地,所以请务必当心!在Git中,误操作导致彻底丢失工作成果地情景并不多见,而这就是其中一个。

场景一:提交之后才发现忘了添加某些文件,或者写错了提交信息,如果你想重新尝试提交,可以使用 --amend选项:

$ git commit --amend

上述命令会提交暂存区的内容。如果你在上次提交后并没有做出任何改动(比如你在上次提交后立即执行上面的命令),那么你的提交快照就不会有变化,但你可以改变提交信息。

和之前提交一样,这次也会启动提交信息编辑器,有所不同的是打开的编辑器中会显示上次提交的信息。你可以像之前一样编辑,保存后就会覆盖之前的提交信息。

比如,你提交过后才意识到忘记了添加某个之前更改过的文件,可以执行类似下面的操作:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

最终只是产生了一个提交,一位内第二个提交命令修正了第一个提交的结果。

 

2.4.1 撤销已暂存的文件

举例来说,假设你更改了两个文件,想要分两次提交,却不小心键入了git add *,把这两个文件都添加到了暂存区。这时,你该如何把文件从暂存区移出呢?其实,git status命令会提示你该如何做。

在“changes to be committed”正下方显示的提示是“使用git reset HEAD <file>...命令把文件移出暂存区”。所以,我们就用提示的办法将文件移出暂存区。

按照该命令操作之后,文件又恢复到了已修改但未暂存的状态。

 

2.4.2 撤销对文件的修改

如果你发现不再需要对某个文件所作的更改,你可以撤销修改并把文件恢复到上次提交时的状态(或是刚克隆仓库后的状态,或是一开始它在工作目录中的状态)。git status命令也会告诉你怎么做。

用git checkout -- <file>即可舍弃对文件的更改。

注意:git checkout -- <file> 是一条危险的命令。执行后任何对file文件做出的修改都会丢失,因为上述命令用之前版本的文件做了覆盖。除非你确定不在需要这些文件,否则不要用这个命令。

 

如果你想保留之前对文件做出的修改,又需要把更改暂时隐藏一会儿,使它们不影响手头的工作,这种情况下使用储藏(stash)和分支的机制更好。

 

2.5 远程仓库的使用

 

2.5.1 显示远程仓库

要查看已经设置了哪些远程仓库,请使用git remote命令。该命令会列出每个远程仓库的简短名称。在克隆某个仓库后,你至少能看到名为origin的远程仓库,这时Git给克隆源服务器取得默认名称。

你也可以使用 -v参数,这样会显示出GIt存储的每个远程仓库对应的URL。

 

2.5.2 添加远程仓库

要添加一个远程仓库,并给它起一个简短名称以便引用,可以执行git remote add [shortname] [url]命令:

$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin    https://github.com/***/ticgit(fetch)
origin    https://github.com/***/ticgit(push)
pb        https://github.com/***/ticgit(fetch)
pb        https://github.com/***/ticgit(push)

现在你可以在命令行中使用pb字符串代替完整的URL。

2.5.3 从远程仓库获取和拉取数据

$ git fetch [remote-name]

这条命令会从远程仓库中获取所有本地仓库没有的数据。当你克隆仓库时,克隆命令会自动添加远程仓库的地址并取名为“origin”。当随后执行 git fetch origin 时,会获取到所有自上次克隆(或获取)之后被推送到服务端的新增的变更数据。但git fetch命令只会把数据拉取到本地仓库,并不会自动将这些数据合并到本地的工作成果中,也不会修改当前工作目录下的任何数据。

如果你有一个跟踪着某个远程分支的本地分支,可以使用git pull命令来自动获取远程数据,并将远程分支合并入当前的本地分支。

 

2.5.4 将数据推送到远程仓库

当你的项目进行到某个阶段,需要与他人分享你的工作成果时,就需要变更推送到远程仓库去。命令如下:

$ git push [remote-name] [branch-name]

比如你想把本地的master分支推送到远程的origin服务器上(Git克隆操作会自动使用上面两个名称作为默认设置),可以用下面的命令,把任意提交推送到服务器端:

$ git push origin master

上述命令能够正常工作的前提是必须拥有克隆下来的远程仓库的写权限,并且克隆后没有任何其他人向远程仓库推送过数据。如果你和别人同时克隆了这个仓库,别人先推送,而你后推送,那么你的这次推送会直接被拒绝。你必须先拉去别人的变更,将其整合到你的工作成果中,然后才能推送。

 

2.5.5 检查远程仓库

要查看某一远程仓库的更多信息,可以使用git remote show [remote-name]命令。如果给该命令提供一个仓库的短名称,比如origin,就会看到一些输出。

$ git remote show origin

执行后会列出远程仓库的URL地址以及每个分支的跟踪信息。

 

2.5.6 删除和重命名远程仓库

可以用 git remote rename来重命名远程仓库。例如,想要把pb重命名为paul,可以执行如下命令:

$ git remote rename pb paul
$ git remote
origin
paul

值得一提的是,上述操作也会更改远程分支的名称。先前的pb/master分支现在变成了paul/master。

有时出于某种原因,需要删除某个远程仓库地址,比如当你迁移了服务器地址,或者不再使用某一镜像,又或是某个参与者退出协作时,就可以使用git remote rm命令,如:

$ git remote rm paul
$ git remote
origin

 

2.6 标记

就像大多数版本控制系统一样,Git可以把特定的历史版本标记为重要版本。其典型应用场景就是标出发布版本(v1.0等)。

 

2.6.1 列举标签

在Git中,列举可用标签的操作很简单,只需键入git tag即可:

$ git tag
v0.1
v1.3

这条命令会按照字母顺序列出所有的标签。列举的顺序先后和标签的重要性无关。

还可以按照某个特定匹配模式搜索标签。举例来说,Git的源代码仓库包括超过500个标签。如果你只想查看1.8.5系列的标记版本,可以执行一下命令:

$ git tag -l "v1.8.5*"
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2

 

 
posted @ 2022-01-08 14:22  禅主  阅读(59)  评论(0编辑  收藏  举报