Git简介

目录


前言
1.配置git
.... 1.1配置文件
.... 1.2默认设置
.... 1.3别名
2. git的基础
.... 2.1创建存储库
.... 2.2文件状态
.... 2.3使用索引
.... 2.4处理提交
.... 2.5查看历史记录
.... 2.6使用远程存储库
3.在git中分支
.... 3.1基本操作
.... 3.2合并分支
.... 3.3退货
4. git中的指针
.... 4.1移动指针
5.推荐读物

前言


Git是最受欢迎的分布式版本控制系统。 [1] [2]

Git的主要目的是保存项目条件不断改善的快照(Pro git,2019)。

本文适用于那些至少具有与git合作的基本知识和技能并且希望扩展其知识的人。

这里只考虑git的技术方面,要更深入地了解git的哲学及其内部实现,我建议您阅读几本有用的书(请参阅推荐阅读 )。

1.配置git


在开始使用git之前,您需要自己配置它!

1.1配置文件


  • / etc / gitconfig-所有用户和存储库的常规设置
  • 〜/ .gitconfig或〜/ .config / git / config-特定的用户设置
  • .git / config-特定存储库的设置

有一支特别的队伍

git config [<>] 

如果需要的话,这将允许您更改git的标准行为,但是您可以手动编辑配置文件(我认为这样更快)。

根据传递给git config(--system,--global,--local)命令的参数,设置将被写入这些文件之一。 每个“级别”(系统级别,全局级别,本地级别)都重新定义了上一个级别的值!

要查看在哪个文件中安装了什么设置,请使用git config --list --show-origin。

忽略文件
在git中,您可以决定将哪些文件提交到哪个提交中,但是也许您希望某些文件永远不在索引和提交中,甚至不出现在未跟踪列表中。 为此,您可以在存储库中创建一个特殊文件(.gitignore),然后在其中写入被忽略文件的模板。 如果不想在每个存储库中创建这样的文件,则可以使用core.excludesfile对其进行全局定义(请参阅“ 有用的设置” )。 您也可以下载正在使用的编程语言的.gitignore文件
要自定义.gitignore,请使用bash正则表达式

1.2默认设置


服务器和客户端都有大量的git设置,这里只考虑基本的客户端设置。

使用方法

 git config name value 

其中name是参数的名称,value是其值,以设置设置。
一个例子:

 git config --global core.editor nano 

将安装默认的编辑器nano。

您可以使用git config --get [name]查看现有参数的值,其中name是要获取其值的参数。

有用的设置:

  • user.name-创建提交时将使用的名称
  • user.email-创建提交时使用的电子邮件
  • core.excludesfile-一个文件,其模板将用于全局忽略特定文件
  • core.editor-默认编辑器
  • commit.template-其内容将用于默认提交消息的文件(请参阅使用commits )。
  • help.autocorrect-设置为1时,git将执行错误编写的命令。
  • credential.helper [模式]-设置凭据存储模式。 [缓存]-凭据会保存一段时间,不会保存密码(--timeout [seconds]删除数据的秒数,默认值为15分钟)。 [store]-凭据以明文形式无限期存储(--file [file]表示存储数据的路径,默认为〜/ .git-credentials)。

1.3别名


如果您不想完整打印Git的每个命令,则可以轻松配置别名。 要创建别名,请使用:

 git config alias.SHORT_NAME COMMAND 

其中SHORT_NAME是要缩写的名称,而COMMAND要缩写的命令。 一个例子:

 git config --global alias.last 'log -1 HEAD' 

执行此命令后,可以通过运行git last来查看有关当前分支上的最后提交的信息。

我建议您使用以下缩写(您也可以定义任何缩写):

  • st =状态
  • ch =结帐
  • br =分支
  • 毫克=合并
  • cm =提交
  • reb =变基
  • lg =“ git log --pretty =格式:'%h-%ar:%s'”

要查看配置设置,请使用:git config --list。

2. git的基础


这里仅列出强制性和有用的参数(在我看来),因为列出所有参数均不合适。 为此,请使用git command -help或--help,其中command是要接收的帮助的命令名称。


2.1创建存储库


  • git init [<options>]-在当前目录(或--separate-git-dir <git_root>之后指定的目录中创建git存储库和.git目录,在这种情况下,.git目录位于另一个位置);
  • git clone [<选项>] [-] <存储库> [<文件夹>] [-o,--origin <名称>] [-b,--branch <分支>] [-单分支] [- -no-tags] [--separate-git-dir <git-directory>] [-c,--config <key = value>]-克隆名称为origin的存储库(或您指定的存储库-o <name> ),位于HEAD指向的分支上(或您指定的-b <branch>分支)。 您也可以通过指定--single-branch仅克隆必要的HEAD分支(或-b <branch>中指定的分支)。 默认情况下,所有标签都是克隆的,但是通过指定--no-tags不能克隆它们。 执行命令后,将在当前目录(或--separate-git-dir <git_root>之后指定的目录中创建.git目录,在这种情况下,.git目录将位于其他位置);

2.2文件状态


要查看存储库中文件的状态,请使用:

 git status [<>] 

该命令可以向您显示:当前处于哪个分支以及所有文件的状态。 没有必需的选项,只有-s可以与有用的选项区分开,这将简要说明文件的状态。

文件生命周期 图片
如您在图片中看到的,可以取消跟踪文件。 监视的文件可以处于3种状态:未修改(未修改),已修改(已修改),准备(已暂存)。
如果添加(使用git add)一个“不受监视”的文件,则它将进入“准备”状态。
如果将文件更改为“未更改”状态,则它将进入“已更改”状态。 如果保存修改后的文件(即处于“已修改”状态),它将进入“已准备”状态。 如果提交文件(即处于“准备”状态),则文件将进入“未更改”状态。
如果HEAD和工作目录中的文件版本不同,则该文件将处于“已修改”状态,否则(如果HEAD和工作目录中的版本相同),该文件将处于“未更改”状态。
如果HEAD中文件的版本与工作目录不同,但与索引中的版本相同,则文件将处于“ Prepared”状态。

此循环可以表示如下:
未修改->已修改->暂存->未修改
也就是说,您修改文件,将其保存在索引中并进行提交,然后重新进行。

2.3使用索引


我希望您了解git存储库的生命周期是什么样的。 现在,让我们看看如何管理git存储库中的索引和文件。

索引是上一次提交和下一次提交之间的中间位置。 您可以在索引中添加或删除文件。 提交时,它从索引而不是从工作空间中获取数据。

要查看索引,请使用git status。

要将文件添加到索引,请使用
 git add [<>] 

有用的git add命令选项:

  • -f,--force-也添加忽略的文件
  • -u,--update-更新跟踪的文件


要从索引中删除文件,可以使用2个git reset和git restore命令。
git-restore-恢复工作树文件。
git-reset-将当前的HEAD重置为指定状态。
实际上,您可以通过两个命令实现相同的目的。

要从索引中删除一些文件,请使用:

 git restore --staged <file> 

这样,您将还原索引(或者从索引中删除特定文件),就像自上次提交以来未对其执行git add一样。 使用此命令,您可以还原工作目录,使其看起来好像在提交后未进行任何更改。 但是此命令的行为有点奇怪-如果您将文件的新版本添加到索引中,则在索引不同于HEAD之前,您无法更改工作目录。 因此,您首先需要还原索引,然后还原工作目录。 不幸的是,用一个命令是不可能做到这一点的,因为当传递两个参数(git restore -SW)时什么也没有发生。 同样,当传递-W时,如果索引和HEAD中的文件不同,则不会发生任何事情。 可能是他们这样做是为了保护您,以便您不会意外更改工作目录。 但是在这种情况下,为什么默认传递-W参数? 总的来说,我不明白为什么要这样做以及为什么要添加此命令。 对我来说,重设可以更好地处理此任务,它还具有更丰富的功能,因为它不仅可以将索引和工作目录移动到最后一个提交,而且还可以移动到其他任何提交。

但是开发人员自己建议使用git restore -S重置索引。 代替git reset HEAD。

使用git status可以查看哪些文件已更改,但是如果您还想知道文件中到底发生了什么更改,请使用以下命令:

 git diff [<options>] 

因此,执行不带参数的命令,可以将索引与工作目录进行比较。 如果已经将文件添加到索引中,请使用git diff --cached查看上一次提交(或您指定的提交)与工作目录之间的差异。 您还可以通过将两个提交或分支作为参数传递来查看它们之间的差异。 示例:git diff 00656c 3d5119显示了提交00656c和3d5119之间的差异。

2.4处理提交


现在您的索引处于正确的状态,是时候提交更改了。 请记住,您在编辑后未运行git add的所有文件均未包含在此提交中。 实际上,其中将包含文件,但只有旧版本(如果有)。

要提交更改,请使用:

 git commit [<>] 

git commit命令的有用选项:

  • -F,--file [file]-从指定的文件写入提交消息
  • --author [作者]-替换提交作者
  • --date [date]-更改提交日期
  • -m,--mesage [消息]-消息提交
  • -a,--all-提交对文件的所有更改
  • -i,--include [files ...]-将指定的文件添加到下一次提交的索引中
  • -o,--only [files ...]-仅提交指定的文件
  • --amend-覆盖先前的提交

您可以使用commit.template定义默认的提交消息。 配置文件中的此伪指令负责其内容将用于默认提交的文件。 示例:git config --global commit.template〜/ .gitmessage.txt。

您还可以更改,删除,合并任何提交。
您可能已经注意到,您可以使用git commit --amend快速覆盖上一次提交。
要更改故事中的提交,请使用

 git rebase -i <commit> 

其中commit是您要更改的链中最重要的提交。

在交互式菜单中执行git rebase -i之后,选择要执行的操作。

  • 选择<commit> =使用提交
  • reword <commit> =使用提交,但更改提交消息
  • 编辑<commit> =使用提交,但停止修复
  • squash <commit> =使用提交,但与先前的提交合并
  • fixup <commit> = as“ squash”,但是跳过提交消息
  • exec <命令> =使用外壳执行命令(行的其余部分)
  • 休息=在这里停止(继续使用“ git rebase --continue”)
  • drop <commit> =删除提交
  • label <label> =给当前HEAD命名
  • 重置<label> =将HEAD重置为指定的标签

更改特定提交的消息。
您必须更改选择才能编辑要更改的提交。
示例:您想要更改750f5ae提交消息。

选择2748cb4第一次提交
编辑750f5ae第二次提交
选择716eb99第三次提交

保存脚本后,您将返回命令行,而git会告诉您下一步该怎么做:

在750f5ae停止...第二次提交
您现在可以修改提交,

git commit-修改

对更改满意后,运行

git rebase-继续

如上所述,您必须运行git commit --amend才能更改提交消息。 然后执行git rebase --continue。 如果您选择了多个提交来更改名称,那么将需要在每个提交上执行这些操作。

删除提交
您必须删除带有提交的行。
示例:您要删除提交750f5ae
您需要从此更改脚本:
选择2748cb4第三次提交
选择750f5ae第二次提交
选择716eb99首先提交
在此:
选择2748cb4第一次提交
选择716eb99第三次提交

合并提交
您必须更改选择以挤压要合并的提交。
示例:您想要组合提交750f5ae和716eb99。
您需要从此更改脚本:
选择2748cb4第三次提交
选择750f5ae第二次提交
选择716eb99首先提交
在这样的
选择2748cb4第三次提交
壁球750f5ae第二次提交
壁球716eb99第一次提交

注意,在交互式脚本中,提交的显示顺序与git log中显示的顺序相反。 使用壁球,您可以将750f5ae提交与716eb99和750f5ae提交与2748cb4结合在一起。 结果,一次提交包含对所有三个更改的更改。

2.5查看历史


使用命令

 git log [<>] [<->] 

您可以查看存储库的提交历史记录。 还有很多用于排序和搜索特定提交的选项。

有用的git log命令选项:

  • -p-显示每次提交的差异。
  • --stat-显示每次提交的已修改文件的统计信息。
  • --graph-显示带有分支和合并历史记录的ASCII图。

您还可以按时间,数量等对提交进行排序。

  • -(n)仅显示最后n次提交。
  • --since,--after-显示在指定日期之后进行的提交。
  • --until,--before-显示在指定日期之前进行的提交。
  • --author-仅显示作者条目与指定字符串匹配的那些提交。
  • --committer-仅显示提交者条目与指定字符串匹配的那些提交。
  • --grep-仅显示其消息包含指定字符串的提交。
  • -S-仅显示其中代码更改导致添加或删除指定行的提交。

以下是一些示例:
git log --since = 3.weeks-显示最近2周的提交
git log --since =“ 2019-01-14”-显示在2019-01-14所做的提交
git log --since =“ 2年1天前”-显示2年零一天前的提交。

您还可以使用以下命令自定义提交输出格式

 git log --format:["format"] 

git log --format的格式化选项。

  • %H-提交哈希
  • %h-缩短的提交哈希
  • %T-树哈希
  • %t-缩短的树形哈希
  • %P-父哈希
  • %p-缩写父哈希
  • %an-作者姓名-%ae-作者电子邮件
  • %ad-作者日期(日期格式可以使用--date =选项设置)
  • %ar-作者的相对日期
  • %cn-提交者名称
  • %ce-提交者电子邮件
  • %cd-提交日期
  • %cr-相对提交日期
  • %s-含量

一个例子:

 git log --pretty=format:"%h - %ar : %s" 

将显示由时间哈希和提交消息组成的提交列表。

2.6使用远程存储库


由于git是一种分布式硬通货,因此您不仅可以使用本地存储库,还可以使用外部存储库。

远程存储库是存储在外部服务器上的项目版本。

要使用外部存储库,请使用:

 git remote [<options>] 

如果您是通过http URL克隆存储库的,则您已经具有指向外部存储库的链接。 否则,您可以添加

 git remote add [<options>] <name> <adres> 

您可以立即使用-f,--fetch提取外部分支(获取外部存储库的分支的名称和状态)。 您只能使用--mirror [=(push | fetch)]将存储库配置为发送或接收数据。 要获取标签,请指定--tags。

要查看连接的外部存储库,请使用不带参数的git remote或git remote -v查看要从存储库发送和接收数据的地址。

要跟踪分支,请使用git branch -u <rep / br>,其中rep是存储库的名称,br是外部分支的名称,而branch是本地分支的名称。 或git branch --set-upstream local_br origin / br,以指示哪个本地分支将监视外部分支。

当您的分支跟踪外部分支时,您可以找出哪个分支(本地分支或外部分支)在后面还是前面以及提交的次数。 例如,如果在提交之后您没有执行git push,那么您的分支将领先于外部的1提交。 您可以通过运行git branch -vv来查找有关此问题的信息,但首先执行git fetch [remote-name](--all可以从所有存储库获取更新)以从外部存储库获取最新数据。 要取消分支跟踪,请使用git branch --unset-upstream [<local_branch>]。

要从外部存储库下载数据,请使用git pull [rep] [branch]。 如果您的分支跟踪外部,则在执行git pull时无法指定它们。 默认情况下,您将从所有受监视的分支接收数据。

要将分支上传到新分支,请使用git checkout -b <新分支名称> <rep /分支>。

要将数据发送到服务器,请使用

 git push [<rep>] [<br>] 

其中rep是外部存储库的名称,br是您要发送的本地分支。 您也可以使用git push origin master:dev这个条目。 因此,您将本地master分支上载到源(但在此处将被称为dev)。 如果您没有权限,则将无法将数据发送到外部存储库。 另外,如果数据在外部分支之前,则将无法将其发送到外部分支(通常,可以使用-f和--forse发送,在这种情况下,您将重写外部存储库上的历史记录)。 如果分支机构正在跟踪外部,则可以省略分支机构的名称。

删除外部分支机构使用

 git push origin --delete branch_name 

有关外部存储库的详细信息(如HEAD所示,用于发送和接收的地址,外部分支,配置为git pull的本地分支和配置为git push的本地链接)

 git remote show <remote_name> 

要重命名外部存储库的名称,请使用

 git remote rename <last_name> <new_name> 

要删除到外部存储库的链接,请使用

 git remote rm <name> 

3.在git中分支


分支是一个功能强大的工具,也是git的主要功能之一,因为它使您可以快速创建版本库并在存储库的不同分支之间进行切换。 分支的主要概念是,您可以从开发主线开始,继续独立进行工作,而不会干扰主线。 分支始终指向其中的最后一个提交,而HEAD指向当前分支(请参见git中的Pointers )。

3.1基本操作


要创建分支,请使用

 git branch <branch_name> [<start_commit>] 

这里branch_name是新分支的名称,start_commit是分支将指向的提交(即,其中的最后一次提交)。 默认情况下,该分支将在父分支的最后一次提交上。

Git分支选项:

  • -r | -a [-合并| --no-merged] — -r. -a. --merged. --no-merged.
  • -l, -f <-> [<->] — -l. , -f. < >.
  • -r (-d | -D) — -r. -d. ( ) -D.
  • -m | -M [< >] < > — / (-m). / , -M.
  • (- | -) [<->] <-> — -c. , -C.
  • -v,-vv-在-v分支上具有最后提交的分支列表。上次提交的受监视分支的列表和状态。

有关更多信息,请参见git branch -h。-帮助。

要切换到分支,请使用git checkout。您还可以通过运行git checkout -b <branch>创建分支。

3.2合并分支


要合并git存储库的2个分支,请使用git merge。

git merge的有用选项:

  • --squash-创建一个提交而不是合并。如果分支上有冲突,则在解决冲突后,将在分支上添加2个提交(来自合并分支的提交+合并提交),但是通过指定此参数,您将仅添加一个提交(合并提交)。
  • --ff-only-如果发生冲突,请勿合并。让其他人解决冲突:D
  • -X [策略]-使用选定的合并策略。
  • --abort-取消合并。

合并过程。
如果您没有在父分支上执行新的提交,那么合并将归结为快进快进,就好像您没有在创建新分支一样,所有更改都在此发生(在父分支上)。

如果您在两个分支上都提交了提交,但没有产生冲突,则合并将在“递归策略”中进行,也就是说,您只需要创建一个合并提交即可应用更改(使用--squash选项以避免创建额外的提交) 。
如果您在对同一文件的相同部分进行了不同更改的两个分支上都进行了提交,则必须解决冲突并提交合并提交。

解决冲突时,您需要从两个分支中选择要保留的更改部分。当您打开有冲突的文件时,它将包含以下内容:
<<<<<<< HEAD
当前分支的最后一次提交的版本
======
合并分支的最后一次提交的版本
>>>>>>>这里的名称我们与之合并的分支

解决了冲突之后,您必须通过提交来完成合并。

在冲突期间,您可以查看哪些文件存在哪些差异。
git diff --ours-合并之前和之后的
差异git diff --theirs-合并之前和之后的合并分支的差异git diff --base-合并之前和之后
两个分支的差异

如果您不想允许合并,则可以使用各种合并策略,或者选择“我们的”版本(即位于当前分支上的版本),或者选择位于合并的分支上的“其”版本而无需更正冲突。分别运行git merge --Xours或git merge --Xtheirs。

3.3重新


重新使用-“重新使用记录的解决方案”-“重新使用保存的冲突解决方案”。rerere机制能够记住您过去解决冲突的特定部分的方式,并在下次发生冲突时自动纠正冲突。

要启用重做

 git config --global rerere.enabled true 

您还可以通过在所需存储库中创建.git / rr-cache目录来启用rerere。

使用git rerere status可以查看rerere合并之前为快照保存了哪些文件。

使用git rerere diff查看当前冲突状态。

如果在合并过程中显示:使用以前的分辨率解决了“ nameFile”问题。因此,rerere已经使用缓存解决了冲突。

要取消自动冲突解决方案,请使用git checkout --conflict = merge,以便取消自动冲突解决方案,并将文件返回冲突状态以进行手动解决。

4. git中的指针


git具有类似HEAD分支的指针。实际上,一切都很简单,HEAD指向当前分支,而该分支指向其中的最后一个提交。但是为了理解,最好想象HEAD指示最后一次提交。

4.1移动指针


Pro git书提供了一个很好的示例,说明了如何管理存储库,因此我也会坚持使用。想象一下,Git管理着三棵不同的树的内容。在此,“树”是指“文件集”。
在常规操作中,Git管理三棵树:

  • HEAD-上一次提交的快照,下一次提交的快照
  • 索引-下一个即将提交的快照
  • 工作目录-沙箱

实际上,git提供了用于操纵所有三棵树的工具。接下来,将讨论git reset命令,该命令允许您使用存储库的三棵树。

使用此命令的各种选项,您可以:

  • --soft-仅重置HEAD
  • --mixed-重置HEAD和索引
  • --hard-重置HEAD,索引和工作目录

通过重置意味着移至指定的提交。默认值为--mixed。

示例1.您进行了3次额外的提交,每个提交都带来了很小的更改,并且您想要进行其中的一个更改,因此您可以使用git reset --soft移动HEAD指针,同时保持索引和工作目录不变并提交。结果,您的故事看起来就像一次提交中发生的所有更改。

示例2.您向索引中添加了额外的文件,并希望从那里删除它们。您可以为此使用git reset HEAD <files ...>。还是您希望提交文件看起来像几次提交。如前所述,您可以将索引重置为任何提交,而与git restore不同,git restore仅重置为最后一次提交。只有使用混合选项,您才能对指定文件执行操作!

例3.您开始在项目上开发新功能,但是突然老板说不再需要它,并且您很生气地执行git reset –在未开始工作之前很难返回索引,文件和HEAD功能。第二天,您将被告知该功能仍应删除。但是该怎么办?如何前进,因为您已经回滚了所有3棵树,现在您无法使用git log在历史记录中找到它们。有一个解决方案-这是git reflog链接日志。使用此命令,您可以看到HEAD指向的位置,它不仅会沿提交历史记录向下移动,还可以向上移动。该日志是每个用户本地的。

总的来说,我认为您可以拿出比我更多的例子。总之,我可以说,使用git reset可以做魔术...

5.


  1. Pro git — Scott Chacon
  2. Git — . , ,
  3. Git Essentials — F. Santacroce
  4. Git: Version Control for Everyone (2013) — R. Somasundaram
  5. Version Control with Git: Powerful tools and techniques for collaborative software development (2009) — J. Loeliger, M. McCullough
  6. Practical Git and GitHub (2016) — D. Cruz
  7. Git in Practice (2016) — M. McQuaid
  8. Git Best Practices Guide (2014) — E. Pidoux
  9. Learn Enough Git to Be Dangerous (2016) — M. Hartl
  10. Learn Version Control with Git: A step-by-step course for the complete beginner (2014) — T. Günther
  11. Git: Learn Version Control with Git: A step-by-step Ultimate beginners Guide (2017) — D. Hutten
  12. Pragmatic Guide to Git (2010) — S. Travis
  13. Git (2016) — .
  14. A Hacker's Guide to Git (2014) — J. Wynn
  15. Practical Git and GitHub (2016) — D. Cruz
  16. Deploying to OpenShift(2018) — G. Dumpleton
  17. Git for Teams (2015) — Emma Jane Hogbin Westby

Source: https://habr.com/ru/post/zh-CN472600/


All Articles