面向工资编程,面向面试学习!

添加更新到仓库

当我们有了 Git 仓库后,我们可能会创建一些未跟踪新文件到仓库中、修改已经跟踪的文件、删除已经跟踪的文件、查看之前的修改历史,经过一系列操作后,我们将文件再次提交到仓库。Git 为这些操作提供了很方便的命令。

查看当前文件状态

Git 使用用 git status 命令来查看当前仓库下的文件处于什么状态。 如果在克隆仓库后立即使用此命令,会看到类似这样的输出:

git status
On branch master
nothing to commit, working directory clean

意思是当前处于master分支,master分支是默认分支,我们将在 Git 分支 详细讲解分支的使用。另外当前分支下没有什么要提交的文件,工作目录是干净的。这表明工作目录下面没有处于未跟踪状态的新文件,同时所有已跟踪文件在上次提交后都没有修改过。

我们在前面初始化的 git_tutorial 项目中创建一个 git_status.html 文件,文件内容如下:

如果之前不存在这个文件,使用 git status 命令将会看到一个新的未跟踪文件:

git status
On branch master
Untracked files:
  (use "git add ..." to include in what will be committed)

        git_status.html

nothing added to commit but untracked files present (use "git add" to track)

在状态信息中我们看到新建的 git_status.html 文件的状态为 Untracked ,表明目前仓库中没有跟踪这个文件。

暂存未跟踪的文件

在项目中新建文件后,新建的文件处于未跟踪(Untracked)状态,想要跟踪这个文件,可以使用 git add 命令。我们运行 git add git_status.html 来跟踪 git_status.html 文件。

此时再运行 git status 命令,会看到 git_status.html 文件已被跟踪,并处于暂存状态:

git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        new file:   git_status.html

我们看到当前处于 master 分支,已在暂存区等待提交的文件是 git_status.html。git add 命令使用文件路径或目录路径作为参数;如果参数是目录路径,该命令将递归地将该目录下的所有文件添加到缓存区。

暂存已修改的文件

当已跟踪的文件被修改后将变成已修改状态,我们将已被跟踪的 README.md 文件的内容修改为下面的:

# 盘古教程(panku.pro)Git Tutorial
我的 git 学习笔记  
git init 初始化 git 仓库  
git clone 克隆仓库  
git status 查看文件  
git add 添加文件到缓存区  

然后运行 git status 命令,会看到下面内容:

git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        new file:   git_status.html

Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   README.md

文件 README.md 出现在 Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。 要暂存这次更新,需要运行 git add 命令。 这是个多功能命令:可以用它来跟踪新文件,或者把已修改状态的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。 我们再次运行 git add README.md 将"README.md"放到暂存区,然后再看看 git status 的输出:

git add README.md
git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        modified:   README.md
        new file:   git_status.html

现在两个文件都已暂存,下次提交时就会被提交到仓库。 我们再次把 README.md 文件修改为如下内容:

# 盘古教程(panku.pro)Git Tutorial
我的 git 学习笔记  
git init 初始化 git 仓库  
git clone 克隆仓库  
git status 查看文件状态信息  
git add 可以用它来跟踪新文件,或者把已修改状态的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等  

再次运行 git status 看看:

git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        modified:   README.md
        new file:   git_status.html

Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   README.md

我们发现 README.md 文件同时出现在暂存区和非暂存区,这是由于 Git 只暂存了你运行 git add 命令时的版本, 如果你现在提交,README.md 的版本是你最后一次运行 git add 命令时的那个版本,而不是你运行 git commit 时,在工作目录中的当前版本。 所以,如果运行了 git add 之后又修改了的文件,需要重新运行 git add 把最新版本重新暂存起来:

git add README.md
git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        modified:   README.md
        new file:   git_status.html

简短输出

我们再次修改下 README.md 文件保存,然后在 git_tutorial 目录中新建 git_add.html 文件,文件内容如下所示:

接着运行 git status -s 查看状态简短信息:

git status -s
MM README.md
A  git_status.html
?? git_add.html

我们发现新添加的未跟踪文件前面有 ?? 标记,新添加到暂存区中的文件前面有 A 标记,修改过的文件前面有 M 标记。 出现在右边的 M 表示该文件被修改了但是还没放入暂存区,出现在靠左边的 M 表示该文件被修改了并放入了暂存区。 上面的状态信息显示: README 文件在工作区被修改了并提交到暂存区后又在工作区中被修改了,所以出现了两个M,git_status.html 是新添加的并且被放入了暂存区, git_add.html 是新添加的并且处于未跟踪状态。

忽略文件

在进行协作开发代码管理的过程中,常常会遇到某些临时文件、配置文件、或者生成文件等,这些文件由于不同的开发端会不一样,如果使用git add . 将所有文件纳入git库中,那么会出现频繁的改动和push,这样会引起开发上的不便。
Git可以很方便的帮助我们解决这个问题,那就是建立项目文件过滤规则。
git中提供两种过滤机制,一种是全局过滤机制,即对所有的git都适用;另一种是针对某个项目使用的过滤规则。个人倾向于第二种。
以 git_tutorial 项目为例,该项目用 html 开发,对于 webstorm 编辑器生成的 .idea 文件夹,我希望不加入git管理。
在 git_tutorial 目录下建立.gitignore文件:vim .gitignore ,内容如下:

.idea

文件 .gitignore 的格式规范如下:

  • 所有空行或者以 # 开头的行视为注释,会被 Git 忽略。
  • 匹配模式可以以(/)开头防止递归。
  • 匹配模式可以以(/)结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
  • 星号(*)匹配零个或多个任意字符。
  • 使用两个星号(*) 表示匹配任意中间目录,比如 a/**/z 可以匹配 a/z , a/b/z 或 a/b/c/z 等。
  • [an9] 匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 n,要么匹配一个 9)。
  • 问号(?)只匹配一个任意字符。
  • 如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。

GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表,你可以在 https://github.com/github/gitignore 找到它.

查看已暂存和未暂存的修改内容

git status 命令只能看到项目里面文件的状态,不能看到具体修改了什么内容,Git 使用 git diff 命令来查看尚未暂存文件的修改内容。 若要查看已暂存的将要添加到下次提交里的内容,可以用 git diff --cached 命令。(Git 1.6.1 及更高版本还允许使用 git diff --staged,效果是相同的)。git diff 将通过文件补丁的格式显示具体哪些行发生了改变。

运行 git status 命令查看项目下文件的状态:

git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        modified:   README.md
        new file:   git_status.html

Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   README.md

Untracked files:
  (use "git add ..." to include in what will be committed)

        .gitignore
        git_add.html

使用 git diff 查看尚未暂存的改动:

使用 git diff 查看尚未暂存的改动

使用 git diff --cached 查看已经暂存起来的变化:

使用 git diff --cached 查看已经暂存起来的变化

提交更新

Git使用 git commit 命令来把暂存区提交到仓库里面,每次提交前先运行 git status,看看所有文件是否都已暂存起来了,否则使用 git add 添加到暂存区,然后再运行提交命令 git commit:

git add .gitignore git_add.html README.md
git commit

运行 git commit 命令后会启动文本编辑器以输入本次提交的说明。 (默认会启用 shell 的环境变量 $EDITOR 所指定的软件,一般都是 vim 或 emacs。也可以使用 git config --global 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
# Changes to be committed:
#       new file:   .gitignore
#       modified:   README.md
#       new file:   git_add.html
#       new file:   git_status.html
#

可以看到默认的提交消息中包含最后一次运行 git status 的输出,放在注释行里,另外开头还有一空行,供你输入提交说明。 (如果想要更详细的对修改了哪些内容的提示,可以用 -v 选项,这会将你所做的改变的 diff 输出放到编辑器中从而使你知道本次提交具体做了哪些修改。) 退出编辑器时,Git 会丢掉注释行,用你输入的附带信息生成一次提交。
也可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行,如下所示:

git commit -m ".gitignore, git add, git status"
[master dbca6fc] .gitignore, git add, git status
 Date: Tue Dec 10 15:19:36 2019 +0800
 4 files changed, 33 insertions(+), 3 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 git_add.html
 create mode 100644 git_status.html

可以看到,提示信息显示了当前是在那个分支(master)提交的,本次提交的完整 SHA-1 校验和是什么(dbca6fc),本次提交有多少文件修订过,多少行添加和删改过。
提交时记录的是放在暂存区域的快照。 任何还未暂存的仍然保持已修改状态,可以在下次提交时纳入版本管理。 每一次运行提交操作,都是对你项目作一次快照,以后可以回到这个状态,或者进行对比。

跳过使用暂存区域

有时候将已修改状态的文件添加到暂存区然后提交太麻烦,我们能否跳过暂存区直接提交呢? Git 提供了一个跳过使用暂存区域的方式, 只要在 git commit 提交的时候加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤。我们先在 git_tutorial 项目下新建 git_init.htm, git_clone.html 文件,文件内容为空,将他们添加到仓库里面:

touch git_init.htm git_clone.html
git add git_init.htm git_clone.htm
git commit -m "git init , git clone"
[master 8df7953] git init , git clone
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 git_clone.htm
 create mode 100644 git_init.htm

然后把 git_init.htm 文件和git_clone.htm 文件修改为如下内容:

git_init.htm 文件

git_clone.htm 文件

然后运行 git status:

git status
On branch master
Changes not staged for commit:
  (use "git add ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        modified:   git_clone.htm
        modified:   git_init.htm

我们看到git_clone.htm、git_init.htm 处于已修改状态,并且还没有添加到暂存区。我们直接使用 git commit -am 提交:

git commit -am "git clone, git init"
[master 8fb8a5d] git clone, git init
 2 files changed, 26 insertions(+)

没有 git add git_clone.htm git_init.htm,直接提交上去了。

移除文件

想从 Git 中移除某个文件,就必须要从已跟踪文件清单(暂存区)中移除,然后提交。 可以用 git rm 命令移除文件,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。 如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 “Changes not staged for commit” 部分(也就是 未暂存清单)看到。我们添加个delete_file.txt文件到仓库,然后 rm 删除它实验下:

touch delete_file.txt
git add delete_file.txt
git commit -m "add delete_file.txt"
[master 91aa8f9] add delete_file.txt
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 delete_file.txt

rm -f delete_file.txt
git status
On branch master
Changes not staged for commit:
  (use "git add/rm ..." to update what will be committed)
  (use "git checkout -- ..." to discard changes in working directory)

        deleted:    delete_file.txt

然后再运行 git rm 记录此次移除文件的操作:

git rm delete_file.txt
rm 'delete_file.txt'

git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        deleted:    delete_file.txt

git commit -m "delete delete_file.txt"

下一次 git commit 提交时,该文件就不再纳入版本管理了。 如果删除之前修改过并且已经放到暂存区域的话,则必须要用强制删除选项 -f(译注:即 force 的首字母)。 这是一种安全特性,用于防止误删还没有添加到快照的数据,这样的数据不能被 Git 恢复。

另外一种情况是,我们想把文件从 Git 仓库中删除(即从暂存区域移除),但是希望文件保留在当前工作目录(磁盘)中。 我们可以使用 --cached 选项:

git rm --cached README.md

git rm 命令后面可以列出文件或者目录的名字,也可以使用 shell 所使用的简化了的正则表达式来匹配。 例如:

git rm log/\*.log

注意到星号 * 之前的反斜杠 \, 因为 Git 有它自己的文件模式扩展匹配方式,所以我们不用 shell 来帮忙展开。 此命令删除 log/ 目录下扩展名为 .log 的所有文件。 类似的例如:

git rm \*.pyc

该命令删除扩展名为 .pyc 的所有文件。

移动或重命名文件,目录或符号链接

Git 使用 git mv 命令来移动或重命名文件,目录或符号链接,命令格式如下:

git mv file_from file_to

我们将 README.md 重命名为 README:

git mv README.md README
git status
On branch master
Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        renamed:    README.md -> README
git commit -m "chang file name"

运行 git mv 就相当于运行了下面三条命令:

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

分开操作 Git 也会意识到这是一次改名,两者唯一的区别是,git mv 是一条命令而另一种方式需要三条命令,直接用 git mv 简洁得多。