《Pro Git》阅读笔记(0)最基本的操作——用户配置、commit等

版权声明:本文为博主原创文章,如未特别声明,均默认使用CC BY-SA 3.0许可。 https://blog.csdn.net/Geek_of_CSDN/article/details/81414583

本博文大部分内容将来自于《Pro Git》,这是一本CC BY-NC-SA 3.0的书,所以可以随便下载来看(但是不能够用在商业用途上),有兴趣的话还是直接下载吧,阅读这本书的英文阅读能力要求也不高(大部分时候只需要读懂指令对应的用途就可以了)。实在是英语苦手还是有中文版

其实Git就是个工具,所以这本书的阅读笔记也只是用来记录这个工具的使用方法/指令而已。这里先记录下最基本的操作(学了之后基本上就可以立马参与到项目开发中的操作)。

Git是什么

Git就是一个版本控制工具,你只需要知道借助这个工具可以很好地控制你或者团队的代码版本,查看你或者团队某次操作中增加或者删除了什么代码(想看更加多相关信息的话就自己下载《pro git》来看)。

Git安装及配置

git安装

安装的话直接上git官网,windows平台下载安装包(自己找),linux基本上用sudo apt-get install git或者sudo yum install git就可以了,这些指令官网都有(一定要养成看官方文档的好习惯),具体的安装步骤都已经是很傻瓜化了,所以就不细讲了。当然也可以从源码开始编译安装,但是贫僧没这个需求所以就懒得做了。git有gui工具(貌似是叫tortoise还是什么的),但是要另外下载。但是gui工具不是万能的,而且学会了命令行的话gui也就不用学了(因为其实gui工具只是把某些指令给封装好了而已。。。),所以下面的内容都是关于怎么在命令行下使用git的(即只记录操作相关的指令)。

git配置

安装好之后使用git之前还需要进行有一些配置(就好像创建账户一样,目的就是为了方便团队管理代码,不然找到bug都不知道该拿谁祭天)。下面提到的配置步骤只需要进行一次(前提是git的数据在之后的使用中都不会受到莫名其妙的损坏,例如遭遇了来自愤怒的程序员的sudo rm -rf /*式毁灭性打击)。

git自己有一个工具(也会是到时候使用的命令)git config,这个工具就是用来配置git的。这个工具修改的数据通常来自:

  1. /etc/gitconfig,明显是linux平台下才有的东西,这是个系统级的配置文件,保存的是系统级的配置,对所有用户有效。要在用git config时搭配--system来修改配置(要有root权限)
  2. ~/.gitconfig或者~/.config/git/config文件,这个的话就是用户级的了,只对当前用户有效(其实和linux系统的设定差不多,毕竟都是林纳斯弄出来的东西。。。),要修改的话就要git config --global
  3. repo里面的.git/config,这个类似于只在这个repo中有效的设置变量,只有在路径处在这个repo路径下的时候设置才会起效。默认修改的都是这个文件的配置,不过也可以用--local来指定修改这个文件下的配置

上面的排列顺序其实是有意义的,越后面出现的优先级越高(也就是git会最优先使用第3个列出来的文件里面的设置)。

如果是windows下的话git会用“HOME”环境变量指定的目录下的.gitconfig文件(所以要小心这个环境变量别设置错了,或者和别的软件设置的变量冲突,本文后面就提到了这种情况,默认HOME是指向C:\Users\$USER)。同时还有系统级的配置文件会出现在C:\Documents and Settings\All Users\Application Data\Git\config(如果是windows xp的话),C:\ProgramData\Git\config(Vista及后面的版本),这个文件里面的内容只能够在admin权限下用git config -f <file>修改。

用户/身份配置

用户名字、邮箱的配置很简单,但是又很重要(因为要git的commit信息要用到这些信息,并且会一直记录在你创建的commit信息中,方便管理员在找到bug的时候拿你来祭天)。

$ git config --global user.name "你的名字"
$ git config --global user.email 你的邮箱地址@xx.com

这是系统级的配置,如果想要在某个项目里面用另外一套配置的话就将路径切换到那个repo中,并直接用上面的git config *****,但是没有--global这个flag。例如在某个repo下使用git config user.name "xxx"

然后可以给git指定一个编辑器,如果没有自己另外指定的话git会默认使用系统默认的编辑器:

$ git config --global core.editor emacs

上面的指令就把git的编辑器指定成了emacs(其实贫僧不怎么用这款编辑器,这里只是个例子),如果是windows平台的话就要指定完整路径(并且指向的是一个可执行文件),例如:

$ git config --global core.editor "'C:/Program Files/Notepad++/notepad++.exe' -multiInst -nosession"

上面的例子就把notepad++(贫僧还是挺喜欢用这款编辑器的)设置成了git的默认编辑器了。

贫僧在windows平台下使用git,貌似没有设置,所以默认的编辑器是类似vim那样的编辑器(可能设置过了,具体的安装步骤忘了,只记得当时是一路按“下一步”的)。

检查设置

如果想要检查设置结果的话就要用到:

$ git config --list

上面这条指令会列出你的所有设置(会比较长),如果只想检查某一项的话:

$ git config 你想检查的那一项的名字

例如:

$ git config user.name

还可以加上--globalflag来检查系统级的设置:

$ git config --global user.name

git自带的帮助文档

$ git help <verb>
$ man git-<verb>

上面两条指令其实效果一样。一个例子“

$ git help config

另一种方式是用-h-helpflag来让git输出简要的帮助,例如:

$ git add -h
usage: git add [<options>] [--] <pathspec>...

    -n, --dry-run         dry run
    -v, --verbose         be verbose
    -i, --interactive     interactive picking
    -p, --patch           select hunks interactively
    -e, --edit            edit current diff and apply
    -f, --force           allow adding otherwise ignored files
    -u, --update          update tracked files
    -N, --intent-to-add   record only the fact that the path will be added later
    -A, --all             add changes from all tracked and untracked files
    --ignore-removal      ignore paths removed in the working tree (same as --no-all)
    --refresh             don't add, only refresh the index
    --ignore-errors       just skip files which cannot be added because of errors
    --ignore-missing      check if - even missing - files are ignored in dry run
    --chmod <(+/-)x>      override the executable bit of the listed files

Git的基本操作

下面正式进入正题:git的操作

获取repo

有两种方式得到repo:

  1. 自己创建一个
  2. 从别的地方(例如github)clone一个别人创建好了的repo下来

创建repo

自己创建的话只需要先进入到目录路径下:

$ cd /c/user/my_project

在git里面用的是/c/代表c盘,不像cmd里面那样的c:\,不过一般都不会搞混,因为在跑命令的时候都会显示出当前目录,可以当成一个提醒:

这里写图片描述

在进入到目标目录之后,就可以开始创建repo了:

$ git init

运行了上面这条指令之后就会创建一个新的文件夹(默认是隐藏的).git,这里面会保存所有git在这个repo运行需要用到的文件。

创建好之后还没有文件被添加到git的监视列表里面,这时候就要用到这条指令来添加监视的文件:

$ git add 文件名

这条指令会让git监视指定的文件(如果想直接开始监视当前目录下所有文件就git add *,贫僧的理解是git命令可以配合正则使用,类似linux命令行)。

在做了改变之后就要commit,这就类似让git对着现在的工作环境拍一次照,只有拍照了之后才能够将现在的状态记录下来(并且后面只能够将工作环境还原到已经拍过照的时刻,没有拍照的话是还原不了的):

$ git commit -m '开始挖坑'

-m用来附上照片的注释,后面可以用git的相关指令查看,相当于是标签,方便使用者知道这次做了什么改动之类的。

clone一个repo

当你想要clone一个repo的时候就要用到clone指令:

$ git clone <url>

例子:

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

git会自动把链接里面的repo下载下来,并保存为repo名字命名的文件夹下,例如这里就是保存在当前目录的libgit2下,没有这个目录的话git会自己创建一个。

如果想要保存在自己命名的文件夹下:

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

这样就会把链接里面的repo保存在当前指令的路径下的mylibgit文件夹里面。

repo中文件状态

repo中文件状态可以总结成这样(图片来自《Pro Git》,中文是贫僧添加的。。。):

这里写图片描述

所有repo下的文件可以大概分成两种状态:tracked和untracked的,tracked就是git知道的并且在记录改动的,untracked的就是git不记录改动的(可以想象成没有登记户口的)。tracked里面又可以分成unmodified、modified和staged,具体怎么分的就看上面那张图。

如果要查询当前repo下文件的状态可以用:

$ git status

git会列出所有不在unmodified状态的文件,可以针对这些文件做相应的动作。

例如你添加了一个README文件到了repo中:

$ git status
On branch master
Your branch is up-to-date with 'origin/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 status指令,git就会告诉你有一个新文件未添加到git的监视列表中。

添加文件到监视列表中

如果想要将这个文件添加到监视列表,那么要用这个指令:

git add 文件/文件夹名

如果是文件夹名的话那么就会自动添加文件夹下面的所有文件到gi的监视列表中。

接着上面的例子:

$ git add README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file: README

README文件在添加进来的时候就已经是staged了(不清楚的话看上面的状态图),这时候其实就已经可以commit了,commit之后git会记录下当前状态下README的文件的状态,恢复到commit的这个状态时README文件的内容也会被恢复到add时的内容。

stage一个modified状态的文件

用到的命令还是上面出现的:

$ git add 文件名

这个指令其实是多功能的指令,能够用来让git开始track一个文件,或者是stage一个文件(这句话看起来怪怪的,但是最好还是习惯这种称呼,因为git里面显示出来的状态或者指令就是这些动词)。

例子,假设已经开始track一个名为“CONTRIBUTING.md”的文件,然后改动了它,那么:

$ git status
On branch master
Your branch is up-to-date with 'origin/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

参考上面的状态表,就可以知道为什么这个文件现在处在这个状态。

为了stage这个文件,那么就要用到add指令:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file: README
    modified: CONTRIBUTING.md

贫僧对stage的理解就是将当前改动拍照,而commit才是真正的将照片保存到档案里面的动作(记录到档案里面的照片才可以重新调出来)。

然后这时候你贼心不死,又改动了文件并添加了一个bug,再用git status看一下repo下文件状态:

$ git status
On branch master
Your branch is up-to-date with 'origin/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

会看到改动的文件有两个modified状态,这是因为git之前已经stage了一个改动,这时候再改动,那么就会出现还没有stage的modified状态,所以看起来是重复出现了的两个状态,其实是不同的。要处理这种情况就只需要重新stage一次(重新拍一次照更新状态),就可以了。

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file: README
    modified: CONTRIBUTING.md

简略输出status

直接用git status觉得输出太繁杂,想要更加简洁的输出?

$ git status -s
 M README
MM Rakefile
A lib/git.rb
M lib/simplegit.rb
?? LICENSE.txt

用上面的指令就可以输出简洁的status结果,??是untrackeed,add的新文件是A,modified的文件是MMM也是,只是一次stage了一次没有stage)。注意其实这些输出的状态是有两列的,第一列代表stage的状态,第二列代表工作空间的状态(就是还没stage的状态),所以README是改动了但是没有stage,lib/simplegit.rb是改动了而且stage了,而Rakefile是有一次stage了的改动和一次stage之后的改动。

让git忽略某些文件

有时候你会在repo下编译文件,而git不能够追踪二进制文件的变换(可以知道改变了,但是不知道哪里变了,所以git不能够用在图片、视频的版本控制上),所以会希望git忽略掉这些文件,而只追踪代码这些纯文本文件的版本变化。这时候就需要创建一个.gitignore文件(可以用正则):

$ cat .gitignore
*.[oa]
*~

上面是书中的例子,这个内容能够让git忽略掉以.o或者.a结尾的文件,以及名字以~结尾的文件。最好在创建repo的时候就写好.gitignore文件,不然可能会不小心commit了不想commit的文件。

.gitignore的语法

下面是.gitignore的语法(可以先跳过,用到的时候再查):

  1. 空行及以#开头的行会被忽略掉
  2. 可以使用通配符,并且通配符定义的规则可以被运用到repo的所有文件
  3. 在通配符开头用/来避免运用到repo主目录下的子文件夹中
  4. 在通配符结尾用/来指明一个文件夹
  5. 在通配符前面用!来取反(让通配符的工作范围取反,就是只不忽略这一行指定的文件)

书中的例子:

# 忽略所有.a文件
*.a

# track名为lib.a的文件,但是还是忽略其他.a文件
!lib.a

# 只忽略主目录下的TODO文件,但是不忽略子文件夹下的TODO文件
/TODO

# 忽略所有build文件夹下的文件
build/

# 忽略doc文件夹下的.txt文件,但是不会忽略doc下子文件夹的.txt文件
doc/*.txt

# 忽略所有doc及doc的子文件夹下的.pdf文件
doc/**/*.pdf

还有其他的例子可以在GitHub上面看

注意,可以不只有一个.gitiignore文件,如果是在子文件夹下面出现的.gitignore文件的话那么这个文件只对该文件夹下文件有效(具体细节自己用man gitignore查。。。)。

diff

这应该是一个明星词汇了。。。基本上所有读过《黑客与画家》的人都见到过。可以用git diff这个指令来比较stage的文件和stage之后又修改了的文件之间的区别(例如上面的CONTRIBUTING.md)。

用这个指令可以查看modified状态而且还没有stage的文件的变动:

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
Please include a nice description of your changes when you submit your PR;
  if we have to read the whole diff to figure out why you're contributing
  in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

  If you are starting to work on a particular area, feel free to submit a PR
  that highlights your work in progress (and note in the PR title that it's

这个指令会拿没stage的modified状态的文件和已经stage了的同一个文件进行比较,并且像上面那样输出变动的地方。

如果想要看看stage了之后的文件里面有什么变了,那么就要加上--staged这个flag:

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

和上面这个指令一样的是git diff --cached,作用一样。

注意:diff不会显示出所有做过的改动,只显示没有stage的改动。

除了用diff之外还可以用git difftools,这样可以调用另外的diff工具(例如emerge、vimdiff或者其他的软件),这里就不介绍了(可以通过git difftools --tool-help来看有什么软件是在当前系统上可以用来diff的)。

commit

指令:

$ git commit

注意,没有stage的改动不会进入到commit提交的状态里面去(要stage的话用git add 文件名)。

运行了上面的指令之后就会弹出你为git设置的默认处理器(就是上面设置的core.editor),贫僧的是vim。弹出来之后的信息是这样的:

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
# new file: README
# modified: CONTRIBUTING.md
# ~ ~ ~
".git/COMMIT_EDITMSG" 9L, 283C

这里面的内容就是到时候会记录到commit信息里面的内容,可以自己修改或者添加什么东西。如果想要加入你更改了什么的信息(diff显示的那些),可以用git commit -v。编辑之后退出编辑器就可以了,git会记录下这里面的内容作为commit信息。

或者不用打开编辑器,直接用指令添加commit信息:

$ 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就会输出上面的信息,信息里面包含了提交到了哪个branch里面,commit的SHA-1校验码(在将repo复原到某个commit状态时可能会用到),并显示有多少个文件被改动了,多少行代码添加了或者移除了。

注意,commit只保存stage了的状态,如果不像手动stage的话(直接commit所有改动),那么只需要加个-aflag就可以了:

$ git commit -a -m '这条指令可以直接commit所有改动'

上面的例子只是示范,不要在commit信息里面写这种东西。。。

在repo里面删除文件

git rm 文件名,这样会把文件删除并把改动stage,不然直接删除的话会显示“有改动没有被stage”:

$ 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 文件名的话那么就不会多出个“有改动没有被stage”:

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted: PROJECTS.md

运行了上面的指令之后要commit才能够把文件移除掉。如果在git rm前更改并stage了文件,那么必须要加上-f选项才可以移除,避免意外将更改了的文件在commit前删除了。

如果只是想要让git停止track这个文件,而在现实中保留这个文件的话那么只需要用这个指令:

$ git rm --cached 文件名

上面的指令都可以搭配通配符,例如:

$ git rm log/\*.log

注意不要忽略掉\。上面这个指令会删除掉所有在log/目录下的.log文件。

移动文件

$ git mv 文件当前位置 文件要移动的位置

书上的例子:

$ git mv README.md README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed: README.md -> README

因为和linux系统的mv指令类似,也有着重命名文件的功能,所以git会把上面这个操作理解成重命名。

git mv指令其实和下面这三行指令的操作是有等同作用的:

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

最后git还是把这个操作看作重命名的操作。这个例子的意义在于你可以用别的软件(例如visual studio code或者atom)来对文件进行重命名。

查看commit历史

$ git log

最新的commit会最先输出,并且会列出commit的SHA-1校验码,commit的人的用户名和邮箱地址,commit信息等东东。

这个指令有一堆可以用的flag,下面只记录几个常用的。

-p或者--patch会让输出的信息里面加上改动的信息。

-2,2可以换成别的数字,这可以让git只输出2条或者n条信息。

--stat让git输出简化的历史:

$ git log --stat
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <[email protected]>
Date: Mon Mar 17 21:52:11 2008 -0700

    changed the version number

  Rakefile | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <[email protected]>
Date: Sat Mar 15 16:40:33 2008 -0700

    removed unnecessary test

lib/simplegit.rb | 5 -----
1 file changed, 5 deletions(-)

--pretty用来改变输出格式,要配合选项使用。oneline选项会让git输出一行的commit信息,shortfullfuller用来输出更少或者更多的信息,format用来规范输出格式,例子:

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 changed the version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 first commit
$ git log --pretty=format:"%h - %an, %ar : %s"
ca82a6d - Scott Chacon, 6 years ago : changed the version number
085bb3b - Scott Chacon, 6 years ago : removed unnecessary test
a11bef0 - Scott Chacon, 6 years ago : first commit

format的其他占位符可以看书上43页的列表。

--graph,会让输出commit信息变成ascii图,例子:

$ git log --pretty=format:"%h %s" --graph
* 2d3acf9 ignore errors from SIGCHLD on trap
* 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit
|\
| * 420eac9 Added a method for getting the current branch.
* | 30e367c timeout code and tests
* | 5a09431 add timeout protection to grit
* | e1193f8 support for heads with slashes in them
|/
* d6016bc require time for xmlschema
* 11d191e Merge branch 'defunkt' into local

--since--until,用来输出某日期之后或之前的commit信息,例子:

$ git log --since=2.weeks

--author输出指定作者的commit信息。

--grep用来筛选commit信息,和linux的grep差不多。

-S可以查找添加了某个函数的commit,例子:

$ git log -S 函数名

这里写图片描述

--no-merges会让log不输出merge产生的commit信息。

记录一个意外遇到的错误

error: could not lock config file。。。 后面省略

贫僧是在windows 10下写这篇博文的,结果在创建repo的时候遇到了这个错误,后来查了查,发现原来是环境变量里面因为之前安装了别的软件,那款软件直接添加了一个叫做“HOME”的环境变量,并指向了这款软件的主目录。这个环境变量会导致git的默认HOME目录变成这个变量设置的目录。

解决方法:

  1. 直接删除这个变量
  2. 将这个变量换一个名字

其实就是个环境变量冲突引发的错误,用上面的方法改了下就解决了。

参考

《Pro Git》:基本上这篇文章的内容都是来自这本书(疯狂暗示去看),作者
Pro Git中文版
Pro Git中文版

两本中文版的没怎么看,不知道翻译水平怎么样。。。

git创建:error: could not lock config file

猜你喜欢

转载自blog.csdn.net/Geek_of_CSDN/article/details/81414583