玩转git三剑客


安装

官方安装包下载地址:https://git-scm.com/download/win
验证是否安装成功:

1
2
$ git --version
git version 2.37.3.windows.1

(建议使用比较高的版本,旧版本可能会在git log --all这些结果展示上有些不太友好的差异)

git使用之前要做的最小配置

  1. 配置全局用户信息
1
2
git config --global user.name 'your_name'
git config --global user.email 'your_email@domain.com'
  1. 配置某个git仓库的用户信息
1
2
git config --local user.name 'your_name'
git config --local user.email 'your_email@domain.com'
  1. config的三个作用域(优先级从高到低)
作用域 用法 效果
local git config –local 只对某个仓库有效
global git config –global 对当前用户所有仓库有效
system git config –system 对系统所有登录的用户有效
4. 查看git配置
1
2
3
git config --list --local
git config --list --global
git config --list --system

git项目初始化

  1. 把已有的项目代码纳入git管理
1
2
cd 项目代码所在文件夹
git init
  1. 新建的项目直接用git管理
1
2
3
cd 某个文件夹
git init your_project_name # 会自动创建文件夹
cd your_project_name

了解工作区和暂存区

通过git log查看版本演变历史

  1. 基本命令git log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ git log
commit a0b98ea6769a71901895c5f879b4b23383ba6bcd
Author: xxx
Date: Wed Sep 7 11:20:39 xxx

Move readme.md to readme

commit 63ca73303c196401d6f0312186a11d517c51f749
Author: xxx
Date: Tue Sep 6 11:10:01 xxx

Add refering projects

commit f77ad615d0a091ac22f78f892c4d50077b43096a
Author: xxx
Date: Tue Sep 6 11:01:34 xxx

Add js

  1. 简洁命令命令git log。(这条命令可以帮助你以简洁的方式查看提交记录。它把提交记录浓缩在了一行,而且只保留类似较短的提交哈希值和提交信息)
1
2
3
4
$ git log --oneline
a0b98ea Move readme.md to readme
63ca733 Add refering projects
f77ad61 Add js
  1. 查看指定的最近m个commit,在上面的两个命令里面添加 -nm即可
1
2
3
#最近的四次提交 
$ git log -n4
$ git log -n4 --oneline
  1. 图形化查看各个分支的git log
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
$ git log --all --graph
* commit fee6bacc33f975bdb0f9ecd7edc7db5acd5429de (HEAD -> main)
| Author: BugKillerPro <511808895@qq.com>
| Date: Wed Sep 7 15:05:37 2022 +0800
|
| Modify style.css on branch main
|
| * commit 97b461a6abd2c7700cc063b5795ec192d6d7d1c3 (tmp)
|/ Author: BugKillerPro <511808895@qq.com>
| Date: Wed Sep 7 14:46:59 2022 +0800
|
| Add test to branch tmp
|
* commit a0b98ea6769a71901895c5f879b4b23383ba6bcd
| Author: BugKillerPro <511808895@qq.com>
| Date: Wed Sep 7 11:20:39 2022 +0800
|
| Move readme.md to readme
|
* commit 63ca73303c196401d6f0312186a11d517c51f749
| Author: BugKillerPro <511808895@qq.com>
| Date: Tue Sep 6 11:10:01 2022 +0800
|
| Add refering projects
|
* commit f77ad615d0a091ac22f78f892c4d50077b43096a (tag: js01)
| Author: BugKillerPro <511808895@qq.com>
| Date: Tue Sep 6 11:01:34 2022 +0800
|
| Add js
|
* commit 78be6970adb1671a56e4536b7ea2170a4aa0a7cf
| Author: BugKillerPro <511808895@qq.com>
| Date: Tue Sep 6 10:59:30 2022 +0800
|
| Add style.css
|
* commit f51e1172b2dca4aea588ec756f630f5ad803212d
| Author: BugKillerPro <511808895@qq.com>
| Date: Tue Sep 6 10:55:52 2022 +0800
|
| Add index _ log
|
* commit 97ad72879455e51a3529a52806f2ec07f67bc8bd (origin/main, origin/HEAD)
Author: bugmakerprox <112847253+bugmakerprox@users.noreply.github.com>
Date: Mon Sep 5 14:02:11 2022 +0800

Initial commit


同样也可以加上--oneline查看简洁化的log,也可以加上-nm,查看所有分支的最近m条log

通过图形化界面工具查看版本演变历史

输入gitk命令,会弹出图形化工具界面

探秘.git文件夹

  1. 查看所有文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ ls -al
drwxr-xr-x 7 root root 222 9月 7 15:30 .
drwxr-xr-x 3 root root 18 9月 7 16:26 ..
-rw-r--r-- 1 root root 32 9月 7 15:05 COMMIT_EDITMSG
-rw-r--r-- 1 root root 360 9月 7 14:44 config
-rw-r--r-- 1 root root 73 9月 5 14:04 description
-rw-r--r-- 1 root root 103 9月 7 10:54 FETCH_HEAD
-rw-r--r-- 1 root root 546 9月 7 15:30 gitk.cache
-rw-r--r-- 1 root root 21 9月 7 14:52 HEAD
drwxr-xr-x 2 root root 268 9月 5 14:04 hooks
-rw-r--r-- 1 root root 554 9月 7 15:05 index
drwxr-xr-x 2 root root 21 9月 5 14:04 info
drwxr-xr-x 3 root root 30 9月 5 14:04 logs
drwxr-xr-x 32 root root 310 9月 7 16:03 objects
-rw-r--r-- 1 root root 41 9月 7 10:59 ORIG_HEAD
-rw-r--r-- 1 root root 105 9月 5 14:04 packed-refs
drwxr-xr-x 5 root root 46 9月 5 14:04 refs

  1. 几个文件的说明

2.1 refs/文件夹

1
2
3
4
5
6
7
8
9
10
11
$ tree refs
refs/
├── heads
│ ├── main
│ └── tmp
├── remotes
│ └── origin
│ └── HEAD
└── tags
└── js01

2.1.1 heads文件夹– 仓库的分支情况

1
2
3
4
$ cat main
fee6bacc33f975bdb0f9ecd7edc7db5acd5429de
$ cat tmp
97b461a6abd2c7700cc063b5795ec192d6d7d1c3

通过对比上面讲到的“图形化查看各个分支”,可以发现,maintmp文件里存放的分别是这两个分支当前指向的commit,也就是每个分支的最后一个commit
另外,可以通过git cat-file -t查看对象的信息,关于git cat-file的用法,详见cat-file

1
2
$ git cat-file -t fee6bacc33f975bdb0f9ecd7edc7db5acd5429de
commit

所以,refs/heads/目录下的文件内容是commit对象信息。

2.1.2 tags 文件夹 – 仓库的tag信息

1
2
$ cat tags/js01
db9cd1f2ba810d45ab0c214326ad50fc026dd65d

同样,通过git cat-file -t查看对象信息

1
2
$ git cat-file -t db9cd1f2ba810d45ab0c214326ad50fc026dd65d
tag

所以,refs/tags/目录下的文件内容是tag对象信息,再通过git cat-file -p查看一下详细信息

1
2
3
4
5
6
7
8
9
10
$ git cat-file -p db9cd1f2ba810d45ab0c214326ad50fc026dd65d
object f77ad615d0a091ac22f78f892c4d50077b43096a
type commit
tag js01
tagger xxx <email> 1662537810 +0800

js01

$ git cat-file -t f77ad615d0a091ac22f78f892c4d50077b43096a
commit

可以看出,js01这个tag是打在f77ad615d0a091ac22f78f892c4d50077b43096a这次commit上的,和上面“图形化查看各个分支”看到的信息一致。

2.2 HEAD文件
表示当前仓库工作所在的分支,文件内容ref: refs/heads/main ,指向refs/heads下的分支文件

2.3 config文件
表示和本地仓库相关的配置信息,local作用域的信息会写在这里面;同样,编辑该文件,信息也可以从git config --local --list看到

2.4 objects文件夹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
$ tree objects
objects/
├── 06
│   └── cdcb31ac08c3da684741bd9e576d806c02c509
├── 17
│   └── 3e0e863d31a6977e6bea2f5433172c302c7827
├── 2c
│   └── 8d044b64097ced0e003b9bded8ed5397767080
├── 2e
│   └── a71f7370e32c9ab44a475cccbc289f65b2c11d
├── 37
│   └── 809d45bb8f6e7699bc3216a4529b965831280f
├── 50
│   └── b9f19afa5ffe2199377d70208207e692417f9d
├── 63
│   └── ca73303c196401d6f0312186a11d517c51f749
├── 6a
│   └── d4c68d567a1a5b415dcfce2010fce1a60b245f
├── 74
│   └── ce54a5c285bebca10869bfde5a61183f37960d
├── 78
│   └── be6970adb1671a56e4536b7ea2170a4aa0a7cf
├── 7c
│   └── fe3376c0cc252bed22271480b06b642f960f48
├── 87
│   └── b3e92f70e7dfa555f141afeae28a2bc4a343b6
├── 96
│   └── b67e399c8496ec36cbbbcb776eb924fad7f9a7
├── 97
│   ├── ad72879455e51a3529a52806f2ec07f67bc8bd
│   └── b461a6abd2c7700cc063b5795ec192d6d7d1c3
├── a0
│   └── b98ea6769a71901895c5f879b4b23383ba6bcd
├── a3
│   └── 461553e40ba4259a40287239b5c38fb2fb76a7
├── ab
│   └── 80565b73e7d2f0a2b5b9667c0b3470238b0fc0
├── ac
│   └── c1c738d00c0c937ce5d630ef096199f8d8d73f
├── ae
│   └── e37060401d19e7bd9f80b7b33920a000e96b5b
├── b0
│   └── eb6f806441b634f3591e7e3abd87a7754d305a
├── cc
│   └── b7b203933b7f1065b3a338eb321ba55112912f
├── d6
│   └── 5a3bef25228c256c49b2ddf5bac2f367cb75f9
├── da
│   └── f480669aa9256fa18b5c28e467af816f16482d
├── db
│   └── 9cd1f2ba810d45ab0c214326ad50fc026dd65d
├── ef
│   ├── 3f137d8af338a8604544a3e482090684321d93
│   └── b66cbd5ffbfe9578e4aaf7629402a9d943205a
├── f5
│   └── 1e1172b2dca4aea588ec756f630f5ad803212d
├── f7
│   └── 7ad615d0a091ac22f78f892c4d50077b43096a
├── fe
│   └── e6bacc33f975bdb0f9ecd7edc7db5acd5429de
├── info
└── pack

详见Git 内部原理 - Git 对象

commit、tree和blob三个对象之间的关系

了解
12

分离头指针(detached HEAD)情况下的注意事项

常见产生分离头指针的情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$ git log --all --graph --oneline
* fee6bac (HEAD -> main) Modify style.css on branch main
| * 97b461a (tmp) Add test to branch tmp
|/
* a0b98ea Move readme.md to readme
* 63ca733 Add refering projects
* f77ad61 (tag: js01) Add js
* 78be697 Add style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

jw.xu@hz-jw-xu-n MINGW64 /d/github/gitPractice (main)
$ git checkout 78be697 # 该操作会产生分离头指针现象
Note: switching to '78be697'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

git switch -c <new-branch-name>

Or undo this operation with:

git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 78be697 Add style.css

$ git log --all --graph --oneline
* fee6bac (main) Modify style.css on branch main
| * 97b461a (tmp) Add test to branch tmp
|/
* a0b98ea Move readme.md to readme
* 63ca733 Add refering projects
* f77ad61 (tag: js01) Add js
* 78be697 (HEAD) Add style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

分离头指针是指当前正在工作在一个没有分支的状态下,即没有指向任何branch。如果在这种情况下做了变更,然后又切换到其他分支,变更将被清理掉。
当然,也可以利用好分离头指针这个特性,比如我们仅仅需要在某个commit上做一些尝试代码,并不需要记录和提交,尝试完之后,直接切换到其他分支即可,尝试代码会被清理掉。
如果在这种情况下,做了变更,又做了commit,则会出现以下情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ git status
HEAD detached at 78be697
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: styles/style.css

no changes added to commit (use "git add" and/or "git commit -a")
$ git add -u
$ git commit -m "Background to yellow"
$ git log --all --graph --oneline
* a5a8831 (HEAD) Background to yellow
| * fee6bac (main) Modify style.css on branch main
| | * 97b461a (tmp) Add test to branch tmp
| |/
| * a0b98ea Move readme.md to readme
| * 63ca733 Add refering projects
| * f77ad61 (tag: js01) Add js
|/
* 78be697 Add style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

$ git branch
* (HEAD detached from 78be697)
main
tmp

可以看到头指针(HEAD)没有指向任何分支(main或者tmp),如果此时切换到了其他分支:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ git checkout main
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

a5a8831 Background to yellow

If you want to keep it by creating a new branch, this may be a good time
to do so with:

git branch <new-branch-name> a5a8831

Switched to branch 'main'
Your branch is ahead of 'origin/main' by 6 commits.
(use "git push" to publish your local commits)

$ git log --all --graph --oneline
* fee6bac (HEAD -> main) Modify style.css on branch main
| * 97b461a (tmp) Add test to branch tmp
|/
* a0b98ea Move readme.md to readme
* 63ca733 Add refering projects
* f77ad61 (tag: js01) Add js
* 78be697 Add style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

发现,之前的a5a8831 (HEAD) Background to yellow消失了。如果觉得a5a8831很重要,此时还有补救办法,就是上面提示的那样git branch <new-branch-name> a5a8831操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ git branch fix_css a5a8831
$ git branch
fix_css
* main
tmp
$ git log --all --graph --oneline
* a5a8831 (fix_css) Background to yellow
| * fee6bac (HEAD -> main) Modify style.css on branch main
| | * 97b461a (tmp) Add test to branch tmp
| |/
| * a0b98ea Move readme.md to readme
| * 63ca733 Add refering projects
| * f77ad61 (tag: js01) Add js
|/
* 78be697 Add style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

新建了一个fix_css分支,之前的提交a5a8831又回来了。

进一步理解HEAD和branch

HEAD 可以指向branch也可以指向commit

怎么删除不需要的分支

1
2
$ git branch -d 分支名 #
$ git branch -D 分支名

区别:

-d
–delete
Delete a branch. The branch must be fully merged in its upstream branch, or in HEAD if no upstream was set with –track or –set-upstream-to.
-D
Shortcut for –delete –force

怎么修改最新commit的message

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git log --all --graph --oneline -n2
* a5a8831 (fix_css) Background to yellow
| * fee6bac (HEAD -> main) Modify style.css on branch main

$ git commit --amend # 弹出vim修改框
[main 7f04fb2] Modify style.css on branch main amend
Date: Wed Sep 7 15:05:37 2022 +0800
1 file changed, 5 insertions(+)

$ git log --all --graph --oneline -n2
* 7f04fb2 (HEAD -> main) Modify style.css on branch main amend
| * a5a8831 (fix_css) Background to yellow

怎么修改老旧的commit的message

1
2
3
4
5
6
$ git log --all --graph --oneline -n6
* fb1ece1 (HEAD -> main) Add div class style
* 167491f Add green style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

如果我想变更167491f Add green style.css这一次commit的message,从“Add green style.css”变更为“Add red style.css”,可以使用它的父commitf51e117rebase操作:
(tips:如果该commit没有父commit,即是第一个commit,我们可以对选用它的commitID做rebase操作,然后在下面的弹出内容里,把该commit添加进去即可,然后再选择对应的commands)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ git rebase -i f51e117  # -i 交互模式
# 弹出以下内容
pick 167491f Add green style.css
pick fb1ece1 Add div class style

# Rebase 97ad728..63ca733 onto 97ad728 (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified); use -c <commit> to reword the commit message
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.

接下来就是编写对应commit的commands,常见的commands解析如下:

commands 解析
pick(简写p) rebase过程中保留这次commit
reword(简写r) rebase过程中保留这次commit,但是需要重新编辑这次commit的message,使用了这个命令之后,保存退出,将会弹出修改message界面
edit(简写e) rebase过程中保留这次commit,保留commit,但rebase操作执行到该commit时会暂停,用户在此commit基础上进行内容修改(当然,也可以不修改)后,执行git add 目标文件和git commit –amend更新message,然后执行git rebase –continue继续未完成的rebase工作 。这个命令的使用场景是,需要对之前的某一个commit上做内容修改
squash(简写s) rebase过程中保留这次commit, 但将其合并至前一个commit,合并时,自动汇总该commit与上一个commit的message,用户可进行二次编辑message
fixup(简写f) 与squash功能类似,保留commit,将其合并至前一个commit,但是丢弃该commit的message,使用上一个commit的message

这里我们把pick 167491f Add green style.css修改为r 167491f Add green style.css,保存退出之后,弹出修改message页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Add red style.css

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Wed Sep 7 11:20:39 2022 +0800
#
# interactive rebase in progress; onto 63ca733
# Last command done (1 command done):
# reword a0b98ea Move readme.md to readme
# Next command to do (1 remaining command):
# pick 7f04fb2 Modify style.css on branch main amend
# You are currently editing a commit while rebasing branch 'main' on '63ca733'.
#
# Changes to be committed:
# renamed: README.md -> README
#
# Untracked files:
# .gitignore
#

message修改完之后,再次保存退出,将自动弹出:

1
2
3
4
5
6
$ git rebase -i f51e117
[detached HEAD 68c45d1] Add red style.css
Date: Tue Sep 6 10:59:30 2022 +0800
1 file changed, 50 insertions(+)
create mode 100644 styles/style.css
Successfully rebased and updated refs/heads/main.

我们再次查看log:

1
2
3
4
5
6
git log --all --graph --oneline -n6
* 7db15bd (HEAD -> main) Add div class style
* 68c45d1 Add red style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

对比开始之前的log,已经完成了message的修改,只不过commit的ID发生了变更。
(注意,当存在多个分支时,修改多个分支共同路径上的commit的message,将从该commit的父commit开始发生裂变,当前分支该commit的message发生了修改,其他分支该commit的message保持不变)
修改f51e117 Add index _ log前:

1
2
3
4
5
6
7
8
* fd46298 (HEAD -> b1) Add style to b1
| * 72c72b5 (main) Add li to index
|/
* 7db15bd Add div class style
* 68c45d1 Add red style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

修改f51e117 Add index _ log后:

1
2
3
4
5
6
7
8
9
10
* 6f4263f (HEAD -> b1) Add style to b1
* 29ec5c3 Add div class style
* f3f7003 Add red style.css
* 8128f86 Add index _ log after init
| * 72c72b5 (main) Add li to index
| * 7db15bd Add div class style
| * 68c45d1 Add red style.css
| * f51e117 Add index _ log
|/
* 97ad728 (origin/main, origin/HEAD) Initial commit

git rebase变基操作应该只在自己开发的分支上进行,所以通过git rebase -i commitID 修改旧的commit的message应该仅限于自己分支,不要对团队集成路径上/共同路径上的commit的message做变更,以免出现不可预期的trouble.

怎么把多个连续的commit合并成一个commit

1
2
3
4
5
6
7
8
$ git log --all --graph --oneline
* a3d26dc (HEAD -> main) Add 3 div to index
* bac9977 Add 2 div to index
* 2fab0c5 Add 1 div to index
* 7db15bd Add div class style
* 68c45d1 Add red style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

最近的三次comimt都是对index文件的操作,我们可以考虑把它们合并一下:

1
$ git rebase -i 7db15bd 

弹出页面:

1
2
3
4
5
pick 2fab0c5 Add 1 div to index
pick bac9977 Add 2 div to index
pick a3d26dc Add 3 div to index

# Rebase 7db15bd..a3d26dc onto 7db15bd (3 commands)

修改为:

1
2
3
4
5
pick 2fab0c5 Add 1 div to index
s bac9977 Add 2 div to index
s a3d26dc Add 3 div to index

# Rebase 7db15bd..a3d26dc onto 7db15bd (3 commands)

保存退出,弹出页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# This is a combination of 3 commits.
# This is the 1st commit message:

Add 1 div to index

# This is the commit message #2:

Add 2 div to index

# This is the commit message #3:

Add 3 div to index

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Fri Sep 9 14:13:08 2022 +0800
#
# interactive rebase in progress; onto 7db15bd
# Last commands done (3 commands done):
# squash bac9977 Add 2 div to index
# squash a3d26dc Add 3 div to index
# No commands remaining.
# You are currently rebasing branch 'main' on '7db15bd'.
#
# Changes to be committed:
# modified: index.html

# This is a combination of 3 commits.下面添加合并成一个commit的message:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# This is a combination of 3 commits.
Add total 3 div to index,a combination commit message
# This is the 1st commit message:

Add 1 div to index

# This is the commit message #2:

Add 2 div to index

# This is the commit message #3:

Add 3 div to index

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Fri Sep 9 14:13:08 2022 +0800
#
# interactive rebase in progress; onto 7db15bd
# Last commands done (3 commands done):
# squash bac9977 Add 2 div to index
# squash a3d26dc Add 3 div to index
# No commands remaining.
# You are currently rebasing branch 'main' on '7db15bd'.

保存退出:

1
2
3
4
5
$ git rebase -i 7db15bd
[detached HEAD 35a3dea] Add total 3 div to index,a combination commit message
Date: Fri Sep 9 14:13:08 2022 +0800
1 file changed, 15 insertions(+)
Successfully rebased and updated refs/heads/main.

查看log,完成commit合并:

1
2
3
4
5
6
$ git log --all --graph --oneline
* 35a3dea (HEAD -> main) Add total 3 div to index,a combination commit message
* 7db15bd Add div class style
* 68c45d1 Add red style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

怎么把多个不连续的commit合并成一个commit

1
2
3
4
5
6
7
8
$ git log --all --graph --oneline
* 6e38539 (HEAD -> main) Add new annotation to index.html
* b7e7353 Add gree style.css
* 35a3dea Add total 3 div to index,a combination commit message
* 7db15bd Add div class style
* 68c45d1 Add red style.css
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

b7e7353 Add gree style.css68c45d1 Add red style.css都是对style.css的修改,考虑合并成一个commit:

1
$ git rebase -i f51e117

弹出:

1
2
3
4
5
pick 68c45d1 Add red style.css
pick 7db15bd Add div class style
pick 35a3dea Add total 3 div to index,a combination commit message
pick b7e7353 Add gree style.css
pick 6e38539 Add new annotation to index.html

修改为:

1
2
3
4
5
pick 68c45d1 Add red style.css
s b7e7353 Add gree style.css
pick 7db15bd Add div class style
pick 35a3dea Add total 3 div to index,a combination commit message
pick 6e38539 Add new annotation to index.html

保存退出(对于不连续的commit做合并,大概率会遇到冲突,如果有冲突,则解决完文件冲突后使用git add -ugit rebase --continue),弹出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# This is a combination of 2 commits.
# 在此处添加合并后的message
Add some color style.css,combination message of 2 commits
# This is the 1st commit message:

Add red style.css

# This is the commit message #2:

Add gree style.css

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Tue Sep 6 10:59:30 2022 +0800
#
# interactive rebase in progress; onto f51e117
# Last commands done (2 commands done):
# pick 68c45d1 Add red style.css
# squash b7e7353 Add gree style.css
# Next commands to do (3 remaining commands):
# pick 7db15bd Add div class style
# pick 35a3dea Add total 3 div to index,a combination commit message
# You are currently rebasing branch 'main' on 'f51e117'.

查看合并结果:

1
2
3
4
5
6
7
$ git log --all --graph --oneline
* d3a8e50 (HEAD -> main) Add new annotation to index.html
* ad7fa4c Add total 3 div to index,a combination commit message
* 6a384dd Add div class style
* ebd0755 Add some color style.css,combination message of 2 commits
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

消除最近的几次提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$ git log --all --graph --oneline
* e4eb5dd (HEAD -> temp) Add images/wall_paper.jpg
* ad147cf Remove style/style.css
* 67626bb Add some comments
| * 0007ea8 (main) Change styles/style.css to 版本库
| * d3a8e50 Add new annotation to index.html
| * ad7fa4c Add total 3 div to index,a combination commit message
| * 6a384dd Add div class style
|/
* ebd0755 Add some color style.css,combination message of 2 commits
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

$ git reset --hard 67626bb
HEAD is now at 67626bb Add some comments

$ git log --all --graph --oneline
* 67626bb (HEAD -> temp) Add some comments
| * 0007ea8 (main) Change styles/style.css to 版本库
| * d3a8e50 Add new annotation to index.html
| * ad7fa4c Add total 3 div to index,a combination commit message
| * 6a384dd Add div class style
|/
* ebd0755 Add some color style.css,combination message of 2 commits
* f51e117 Add index _ log
* 97ad728 (origin/main, origin/HEAD) Initial commit

git reset --hard commitID,HEAD会指向comitID,并且暂存区和工作区都会恢复到指定commitID的内容。

怎么比较暂存区和HEAD所含文件的差异

1
2
3
4
# 工作区文件修改后,添加到暂存区
$ git add -u
# 比较暂存区和HEAD所含文件的差异
$ git diff --cached

如何让暂存区恢复成和HEAD的一样

即放弃已经add到暂存区的变更

1
2
3
4
# 恢复
$ git reset HEAD
# 查看差异,验证恢复
$ git diff --cached

执行之后,从上一次commit到现在,add到暂存区的变更将会清除,但是本地工作区不会被清除

怎样取消暂存区部分文件的更改

1
2
3
4
5
6
7
8
9
10
$ git status
On branch main
Your branch is ahead of 'origin/main' by 6 commits.
(use "git push" to publish your local commits)

Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: index.html
modified: styles/style.css

index.htmlstyles/style.css两个文件都做了修改,并且已经add到暂存区,同样可以使用git reset命令来取消暂存区某个文件的更改,即把这个文件从上一次commit到现在,add到暂存区的变更将会清除,但是本地工作区不会被清除

1
$ git reset HEAD -- index.html

执行之后,暂存区的index.html文件将和上一次commit时保持一致,如果此时再git commit操作,将会把暂存区styles/style.css的变更提交到版本库。

怎么比较工作区和暂存区所含文件的差异

1
2
# 工作区文件修改之后,添加到暂存区之前,比较工作区和暂存区所含文件的差异
$ git diff [-- filename(多个空格隔开) ]

如何让工作区的文件恢复为和暂存区一样

即放弃从上次add到目前,在工作区的变更

1
2
3
4
5
6
# 恢复指定文件
$ git checkout -- filename
# 恢复当前目录下所有
$ git checkout .
# 查看差异,验证恢复
$ git diff

总结:

查看不同提交的指定文件的差异

1
2
3
4
# 分之间文件差异
$ git diff branch1 branch2 -- filename
# commit间文件差异(commitID1和commitID2可以在不同的分支上)
$ git diff commitID1 commitID2 -- filename

正确删除文件的方法

1
$ git rm filename

如何指定不需要git管理的文件

详见.gitignore

如何将git仓库备份到本地

  1. 哑协议和智能协议
    protocal

protocal_diff

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
$ pwd
/d/github/gitPractice

$ cd ..
# 创建哑协议备份仓库目录
$ mkdir gitPracticeBackUpYa
# 创建只能协议备份仓库目录
$ mkdir gitPracticeBackUpZhiNeng

$ cd gitPracticeBackUpYa/
# 通过哑协议备份到gitPracticeBackUpYa目录
$ git clone --bare /d/github/gitPractice/.git/ ya_xie_yi.git
Cloning into bare repository 'ya_xie_yi.git'...
done.

$ cd ../gitPracticeBackUpZhiNeng/
# 通过智能协议备份到gitPracticeBackUpYa目录,--bare不包含工作区
$ git clone --bare file:///d/github/gitPractice/.git zhi_neng.git
Cloning into bare repository 'zhi_neng.git'...
remote: Enumerating objects: 29, done.
remote: Counting objects: 100% (29/29), done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 29 (delta 10), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (29/29), 22.51 KiB | 5.63 MiB/s, done.
Resolving deltas: 100% (10/10), done.

$ ls
zhi_neng.git/

$ ls ../gitPracticeBackUpYa/
ya_xie_yi.git/

  1. 备份
    backup
1
2
3
4
5
6
7
8
/d/github/gitPractice (temp)
$ git remote -v # 显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
origin https://github.com/bugmakerprox/gitPractice.git (fetch)
origin https://github.com/bugmakerprox/gitPractice.git (push)

# git remote add <shortname> <url> 添加一个新的远程 Git 仓库
$ git remote add zhineng file:///d/github/gitPracticeBackUpZhiNeng/zhi_neng.git

在备份仓库(gitPracticeBackUpZhiNeng)查看

1
2
3
4
5
6
7
8
9
10
11
12
$ pwd
/d/github/gitPracticeBackUpZhiNeng/zhi_neng.git

jw.xu@hz-jw-xu-n MINGW64 /d/github/gitPracticeBackUpZhiNeng/zhi_neng.git (BARE:temp)
$ git branch -av
main 0007ea8 Change styles/style.css to 版本库
* temp 67626bb Add some comments

$ cd ..
$ ls
zhi_neng.git/

在本地仓库推送到远程仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/d/github/gitPractice (temp)
$ git remote -v
origin https://github.com/bugmakerprox/gitPractice.git (fetch)
origin https://github.com/bugmakerprox/gitPractice.git (push)
zhineng file:///d/github/gitPracticeBackUpZhiNeng/zhi_neng.git (fetch)
zhineng file:///d/github/gitPracticeBackUpZhiNeng/zhi_neng.git (push)

$ git add .

$ git commit -m "Add to zhineng"
[temp aa50d7b] Add to zhineng
4 files changed, 31 insertions(+)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/gitPractice.iml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/vcs.xml

在备份仓库(gitPracticeBackUpZhiNeng)查看

1
2
3
4
5
6
7
$ pwd
/d/github/gitPracticeBackUpZhiNeng/zhi_neng.git

$ cd ..
$ ls
zhi_neng.git/

  1. 恢复
    恢复这部分内容,教程里面没有涉及,而且前面两步讲的比较笼统,虽然上面gitPracticeBackUpZhiNenggitPracticeBackUpYa目录并没有工程代码,只备份了.git文件,备份恢复来说已经足够了,下面就讲一下如何利用zhi_neng.git做恢复
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 任意目录
$ git clone file:///d/github/gitPracticeBackUpZhiNeng/zhi_neng.git
Cloning into 'zhi_neng'...
remote: Enumerating objects: 36, done.
remote: Counting objects: 100% (36/36), done.
remote: Compressing objects: 100% (20/20), done.
remote: Total 36 (delta 11), reused 28 (delta 10), pack-reused 0
Receiving objects: 100% (36/36), 23.54 KiB | 3.92 MiB/s, done.
Resolving deltas: 100% (11/11), done.

$ cd zhi_neng/

$ ls
README.md images/ index.html styles/

$ git branch -av
* temp aa50d7b Add to zhineng
remotes/origin/HEAD -> origin/temp
remotes/origin/main 0007ea8 Change styles/style.css to 版本库
remotes/origin/temp aa50d7b Add to zhineng

把本地仓库同步到github

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# git remote add <shortname> <url> 添加一个新的远程 Git 仓库
$ git remote add github git@github.com:bugmakerprox/gitPractice.git
# 查看
$ git remote -v
github git@github.com:bugmakerprox/gitPractice.git (fetch)
github git@github.com:bugmakerprox/gitPractice.git (push)
origin https://github.com/bugmakerprox/gitPractice.git (fetch)
origin https://github.com/bugmakerprox/gitPractice.git (push)
zhineng file:///d/github/gitPracticeBackUpZhiNeng/zhi_neng.git (fetch)
zhineng file:///d/github/gitPracticeBackUpZhiNeng/zhi_neng.git (push)

# push
$ git push github --all
Enumerating objects: 34, done.
Counting objects: 100% (34/34), done.
Delta compression using up to 4 threads
Compressing objects: 100% (29/29), done.
Writing objects: 100% (33/33), 22.97 KiB | 1.35 MiB/s, done.
Total 33 (delta 11), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (11/11), done.
To github.com:bugmakerprox/gitPractice.git
97ad728..0007ea8 main -> main
* [new branch] temp -> temp

不同人修改了不同文件或者不同人修改了同文件的不同区域如何处理

git pull,和远程仓库做个同步(拉去其他人的变更),再git push自己的变更到远程仓库

git pull = git fetch + git merge 详情

不同人同文件的同区域如何处理

  • git pull,和远程仓库做个同步(拉取其他人的变更)
  • 这时会提示发生了CONFLICT,需要先解决冲突,编辑产生冲突的文件(建议通过编译器如Goland自带的Git –> Resolve Conflict来解决)
  • 再通过git status查看冲突是否完全解决
  • 如果是,则通过git commit提交即可完成冲突合并,如果要放弃merge,需要使用git merge --abort来实现。

同时变更了文件名和文件内容如何处理

场景:

  • 甲把文件A.html变更为了B.html,并git push提交到了远程仓库
  • 同时乙在本地对A.html文件内容进行了修改,git push提交到远程仓库,此时会发生! [rejected]提示
    img

解决:
乙需要先git pull,如果有冲突需要和上一步一样解决冲突,如果没有冲突,会发现本地文件A.html变更为了B.html,并且之前在本地对A.html文件内容的修改也会出现在B.html文件,即git智能的帮我们完成了合并,接下来继续commitpush提交到远程仓库即可。

多人修改同一文件的文件名如何处理

场景:

  • 甲把文件index.htm变更为了index2.htm,并commitpush提交到了远程仓库
  • 乙把文件index.htm变更为了index1.htm,并通过commitpush做提交,此时会发生! [rejected]提示
    img

解决:
乙需要先git pull,会提示冲突:
img
查看本地文件,会发现同时出现了index1.htmindex2.htm两个文件,通过git status查看一下:
img
提示非常详细:

1
2
3
both deleted: index.htm
added by us : index1.htm
added by them : index2.htm

同时也给出了操作建议:

1
2
Unmerged pahts:
(use "git add/rm <file>..." as appropriate to mark resolution)

甲和乙协商index.htm最终需要确定的名称之后,比如index1.htm,进行如下操作

  • git rm index.htm
  • git rm index2.htm
  • git add index1.htm
    查看git status:
    img

冲突已经解决,接下来git commitgit push即可。

禁止向集成分支执行git push -f操作

禁止向集成分支执行变更历史的操作

Some tips

  1. windows系统中,git commit -m "Add file or files" 提交说明建议用双引号,以免出现不可预知的错误
  2. git commit -m "Add file or files",提交说明,建议第一个单词(Add)的首字母大写
  3. 对于git已经跟踪的文件,文件内容变更后,建议使用git add -u
  4. 对于git已经跟踪的文件,如果要对其进行重命名,建议使用git mv oldName newName,然后直接commit
  5. git addgit commit -m 可以合并为一个命令git commit -am