Git是开发中常用的分布式代码管理工具,它是Linus为管理Linux内核代码而设计开发的。

本文介绍几个在使用Git管理代码中会遇到的情况。

打标签

在项目开发中当一期的需求开发完成后,我们应该将开发分支的代码合并到主分支上去,并在主分支上打标签说明这期需求的内容功能点。这样方便日后查看版本变更路径或从指定版本中拉取代码另外开发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ git tag #查看所有标签
v0.1
v1.0
...

$ tag -l 'v1.8.*' # 查看所有 v1.8.xxx 分支
v1.8.0
v1.8.1
...

$ git tag -a v1.9.0 -m 'my version 1.9' # 创建标签并备注
$ git show v1.9.0 #查看 标签v1.9.0信息

$ git push origin v1.9.0 # 将标签v1.9.0提交到远程服务器
$ git push origin --tags # 将所有标签提交到远程服务器
$ git push origin --delete tag v1.9.0 # 删除远程服务器 标签
$ git checkout -b version1.8.5 v1.8.5 #从标签v1.8.5拉除一个新分支version1.8.5

在开发中如果你忘记打标签了希望补打,可以先找到需要打标签那次提交的commitID,通过commitID补打标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme

$ git tag -a v1.2 9fceb02

储藏与清理

在日常开发过程中,我们正在在develop分支开发进行的需求,现网突然有个紧急BUG需要修改。这时你需要停下手头的开发切换分支进行Fix。而你开发并没有完成,为了保持版本的清晰性你可以将现有的分支上修改的代码储藏起来,切换到主分支Fix完后再取出储藏的代码继续开发。

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 status #查看当前分支 改动情况
On branch master
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: package.json

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

test.md

no changes added to commit (use "git add" and/or "git commit -a")

$ git stash # 储藏变动的文件 到栈中
$ git stash list # 查看储藏的 代码
stash@{0}: WIP on master: 8aa5ad2 Git Demo
$ git status # git stash 默认值储藏已经被跟踪的文件,如果文件没被跟踪并不会被储藏
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)

test.md

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

$ git stash pop # 取出最近被储藏的文件并删除该栈
$ git stash -u # 无论文件是否被跟踪只要有变化都将 储藏到栈中
$ git status
On branch master
nothing to commit, working tree clean

当有多个储藏的栈时,你可以通过git stash apply stash@{x}来指定取出储藏的文件。删除某个储藏的栈命令是git stash drop stash@{x}

看发过程中如果我们希望移除调未被跟踪的文件可以通过git clean命令

1
2
3
4
$ git clean -d -f -n #-d -f 表强制移除未被跟踪的文件以及空的子目录 -n 表示演示会移除的信息但不会真的移除,如果你没有加 -n 则会真的进行移除操作

# clean 默认是不会移除 在 .gitignore中声明的忽略文件,如果你希望忽略文件也被移除可以添加参数 -x
$ git clean -d -x -f

查看提交日志

git log是我们经常会用的命令,Git提供了多种查下方式方便我们使用。

1
2
3
4
5
$ git log # 列出所有 提交日志,会按照新旧顺序显示出来。先得信息包括唯一的commitID,提交日期,提交人员和备注。
$ git log -p # 显示每次提交,仓库变化的不同点。
$ git log -p -2 #显示最近两次提交,仓库变化的不同点。
$ git log --pretty=oneline # 只显示每次提交的 commitID和备注
$ git log --stat #每次提交的简略的统计信息

通过$ git log --pretty=format可以定制日志显示的格式。例如:

1
2
3
4
$ 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常用的选项有:

选项 说明
%H 提交对象(commit)的完整哈希字串
%h 提交对象的简短哈希字串
%T 树对象(tree)的完整哈希字串
%t 树对象的简短哈希字串
%P 父对象(parent)的完整哈希字串
%p 父对象的简短哈希字串
%an 作者(author)的名字
%ae 作者的电子邮件地址
%ad 作者修订日期(可以用 –date= 选项定制格式)
%ar 作者修订日期,按多久以前的方式显示
%cn 提交者(committer)的名字
%ce 提交者的电子邮件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式显示
%s 提交日期,按多久以前的方式显示

--prettyonelineformatlog选项中的--graph结合使用时尤其有用。这个选项添加了一些ASCC字符串用来形象的展示了分支和合并的历史。

git log拥有一些自己的选项:

选项 说明
-p 按补丁格式显示每个更新之间的差异
–stat 显示每次更新的文件修改统计信息
–shortstat 只显示 –stat 中最后的行数修改添加移除统计
–name-only 仅在提交信息后显示已修改的文件清单
–name-status 显示新增、修改、删除的文件清单
–abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
–relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)
–graph 显示 ASCII 图形表示的分支合并历史
–pretty 使用其他格式显示历史提交信息

git log还提供了一些过滤显示条件的选项,例如:git log --author=fynn90命令只显示作者fynn90的提交记录,结合--pretty=format可以自定义显示的数据和格式。

常用的过滤日志显示选项有:

选项 说明
-(n) 仅显示最近的 n 条提交
–since, –after 仅显示指定时间之后的提交
–until, –before 仅显示指定时间之前的提交
–author 仅显示指定作者相关的提交
–committer 仅显示指定提交者相关的提交
–grep 仅显示含指定关键字的提交
-S 仅显示添加或移除了某个关键字的提交

例子:如果要查看 Git 仓库中,2008 年 10 月期间,Junio Hamano 提交的但未合并的测试文件,可以用下面的查询命令

1
2
3
4
5
6
7
8
$ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \
--before="2008-11-01" --no-merges -- t/
5610e3b - Fix testcase failure when extended attributes are in use
acd3b9e - Enhance hold_lock_file_for_{update,append}() API
f563754 - demonstrate breakage of detached checkout with symbolic link HEAD
d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths
51a94af - Fix "checkout --track -b newbranch" on detached HEAD
b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch

撤销

在日常开发中我们会完成一次commit后在push到远程服务器之前又向对文件进行修改,这时我们就需要对仓库进行撤销操作

合并 commit

commit后,发现还有文件没有添加,可以通过commit --amend合并commit

1
2
3
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

撤销缓存和还原修改的文件

当你将两个有改动的文件通过add添加到暂存区后,想将一个文件从暂存区移除掉并还原修改的文件。:

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
$ git add *
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

renamed: README.md -> README
modified: CONTRIBUTING.md
$ git reset HEAD CONTRIBUTING.md # 将文件从暂存区移除
Unstaged changes after reset:
M CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

renamed: README.md -> 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
$ git checkout -- CONTRIBUTING.md # 撤销对文件的修改
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

renamed: README.md -> README

撤回某次commit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git add .
$ git commit -m 'xxxx'

# 想撤销 commit操作
$ git reset --soft HEAD^

#HEAD^的意思是上一个版本,也可以写成HEAD~1
#如果你进行了2次commit,想都撤回,可以使用HEAD~2

#--soft
#不删除工作空间改动代码,撤销commit,不撤销git add .

#--hard
# 删除工作空间改动代码,撤销commit,撤销git add .
# 注意完成这个操作后,就恢复到了上一次的commit状态。

回滚

如果通过git push推送到远程仓库,我们希望还原操作,这个操作叫做”回滚”!

删除最后一次远程提交

1
2
3
4
5
$ git revert HEAD # 通过 revert
$ git push origin master

$ git reset --hard HEAD^ # 通过 reset
$ git push origin master -f

revertreset区别:

  • revert是放弃指定提交的修改,但是会生成一次新的提交,需要填写提交注释,以前的历史记录都在;
  • reset是指将HEAD指针指到指定提交,历史记录中不会出现放弃的提交记录。

回滚到某次提交

1
2
3
$ git log --pretty=oneline
$ git revert commitID
$ git reset --hard commitID

修改远程仓库地址

1
2
$ git remote rm origin // 删除现有地址
$ git remote add origin [url] // 添加新地址

给已有项目添加git

1
2
3
4
5
6
$ git init // git 项目初始化
$ git add . //
$ git commit -m 'xxx'
$ git remote add origin git@xxxxx
$ git pull --rebase origin master // 如果远程库不为空 必须这一步,如果是空的 可以不执行
$ git push origin master

中文乱码

在Mac下git显示中文字符会出现乱码,可以通过下面命令解决:

1
2
3
4
$ git config --global core.quotepath false
$ git config --global gui.encoding utf-8 // 设置git gui的界面编码
$ git config --global i18n.commitencoding utf-8 // commit log 提交时使用 utf-8 编码
$ git config --global i18n.logoutputencoding gbk // git log 时将 utf-8 编码转换成 gbk 编码,解决Msys bash中git log 乱码

删除已经被跟踪文件或目录

不想被跟踪的文件、目录需要写入.gitignore文件中.如果你想将某个已经被跟踪的文件、目录添加到.gitignore文件中,git还是会跟踪它.

这时你需要告诉 git 不再跟踪它

1
2
git rm --cached 文件名
git rm --cached -r 目录

执行完以上步骤之后,再去执行正常的git status, git add, git commit命令即可。把刚才的操作提交到仓库中即可。

Git 命令图谱

37923f2478edc5709b36562b26c9e008.png

参考

https://git-scm.com/book/zh/v2

https://blog.csdn.net/ligang2585116/article/details/71094887

https://www.git-tower.com/learn/git/ebook/cn/command-line/advanced-topics/undoing-things

https://github.com/geeeeeeeeek/git-recipes/wiki/5.2-%E4%BB%A3%E7%A0%81%E5%9B%9E%E6%BB%9A%EF%BC%9AReset%E3%80%81Checkout%E3%80%81Revert-%E7%9A%84%E9%80%89%E6%8B%A9