Git
1. Git:版本控制
每一次的提取操作,实际上都是一次对代码仓库的完整备份
2. Git中文件的三种状态
已提交(committed),已修改(modified)和已暂存(staged)
已提交表示该文件已经被安全地保存在本地数据库中了;已修改表示修改了某个文件,但还没有提交保存;已暂存表示把已修改的文件放在下次提交时要保存的清单中。
3. 基本的 Git 工作流程如下所示:
-
在工作目录中修改某些文件。
-
对这些修改了的文件作快照,并保存到暂存区域。
-
提交更新,将保存在暂存区域的文件快照转储到 git 目录中。
4. 修改git提交者名称与邮箱
cmd进入dos窗口 输入git config user.name 获取当前的用户名 修改用户名 :输入git config --global user.name “用户名”
–global,代表的是全局 git config --global user.name 获取目标用户名; git config --global user.email 获取目标邮箱名;
git 修改当前的project提交邮箱的命令为: git config user.email 你的目标邮箱名; git 修改当前的project的用户名的命令为: git config user.name 你的目标用户名;
5. Git仓库初始化
要对现有的某个项目开始用 Git 管理,只需到此项目所在的目录,执行
git init
初始化后,在当前目录下会出现一个名为 .git 的目录,所有 Git 需要的数据和资源都存放在这个目录中
6. 把项目文件添加到Git仓库
git add .
// 该命令会把项目文件全部加入Git本地仓库
git commit -m "备注内容"
// 为我们本次提交到版本添加一个备注
git push origin/master
// 把本地仓库中的文件推送到远程仓库 origin/master, origin/master可以随意更换成我们自己想要推送到的分支。
7. Git 克隆
使用场景:当我们想要从某个远程仓库中克隆一份别人的代码,想要参与某个项目的协作开发的时候,可以使用这个命令把代码克隆到本地
git clone url
url 替换成自己clone的地址
8. 检查当前文件状态
git status
9. 忽略某些文件
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表
我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式
.classpath
.springBeans
.project
.DS_Store
.settings/
.idea/
.vscode/
.factorypath
.sts4-cache/
out/
bin/
intellij/
build/
*.log
*.log.*
文件 .gitignore 的格式规范如下:
• 所有空行或者以注释符号 # 开头的行都会被 Git 忽略。
• 可以使用标准的 glob 模式匹配。
• 匹配模式最后跟反斜杠(/)说明要忽略的是目录。
• 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。
10. 查看与暂存区不一样的地方
请注意,单单 git diff 不过是显示还没有暂存起来的改动,而不是这次工作和上次提交之间的差异
只能看未提交部分和之前提交的文件不一样的地方
git diff
查看已经暂存起来的文件和上次提交时的快照之间的差异
git diff --staged
11. 提交
请一定要确认还有什么修改过的或新建的文件还没有 git add 过,否则提交的时候不会记录这些还没暂存起来的变化。所以,每次准备提交前,先用 git status 看下,是不是都已暂存起来了,然后再运行提交命令 git commit:
git commit
commit
每一次运行提交操作,都是对你项目作一次快照
提交时记录的是放在暂存区域的快照,任何还未暂存的仍然保持已修改状态,可以在下次提交时纳入版本管理。每一次运行提交操作,都是对你项目作一次快照,以后可以回到这个状态,或者进行比较
commit -m
对本次提交添加说明
git cpmmit -m "第一次提交"
commit -a
Git 提供了一个跳过使用暂存区域的方式,只要在提交的时候,给 git commit 加上 -a 选项,Git就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤:
其实就是帮助我们省略了 git add . 的操作
git commit -a -m "提交所有"
12. 删除文件
删除暂存区和当前目录下的文件
要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除)
可以用 git rm 命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了
总结 git rm 不仅可以删除跟踪的文件,还可以顺便删除项目目录中的指定文件
注:加上 -f 强制删除
git rm -f demo/src/main/java/io/gao/stream/ss.java
可以删除这个路径的 ss.java 文件
删除暂存区的文件,但是当前目录下仍然想要保存
git rm --cached demo/src/main/java/io/gao/stream/ss.java
多选删除
git rm log/\*.log
注意到星号 * 之前的反斜杠 \,因为 Git 有它自己的文件模式扩展匹配方式,所以我们不用 shell 来帮忙展开(译注:实际上不加反斜杠也可以运行,只不过按照 shell 扩展的话,仅仅删除指定目录下的文件而不会递归匹配。上面的例子本来就指定了目录,所以效果等同,但下面的例子就会用递归方式匹配,所以必须加反斜杠。)。此命令删除所有 log/目录下扩展名为 .log 的文件
总结: 加了 \ 之后只会匹配当前目录下的 .log 文件,不会递归的删除该文件下面文件中的.log 文件
git rm \*~
会递归删除当前目录及其子目录中所有 ~ 结尾的文件
13. 移动文件
要在 Git 中对文件改名,可以这么做
git mv file_path1 file_path2
例如:
git mv demo/src/main/java/io/gao/stream/ss.java demo/src/main/java/io/gao/stream/yy.java
git mv 就相当于运行了下面三条命令
mv README.txt README
git rm README.txt
git add README
14. 查看提交历史
git log
运行结果
commit d435e30993b0431a507c88233aef6e96dcebf878 (HEAD -> master)
Author: 高建强 <gaojianqiang.gjq@alibaba-inc.com>
Date: Tue Dec 7 16:43:11 2021 +0800
ss
commit 1ab46677d0cde984e0d27692510319401924320f
Author: 高建强 <gaojianqiang.gjq@alibaba-inc.com>
Date: Tue Dec 7 16:40:08 2021 +0800
ss
:
展示git提交差异
-p 选项展开显示每次提交的内容差异,用 -2 则仅显示最近的两次更新
git log -p -2
显示结果:是我修改的差异(rename 了文件ss->yy)
Author: 高建强 <gaojianqiang.gjq@alibaba-inc.com>
Date: Tue Dec 7 16:43:11 2021 +0800
ss
diff --git a/demo/src/main/java/io/gao/stream/ss.java b/demo/src/main/java/io/gao/stream/yy.java
similarity index 88%
rename from demo/src/main/java/io/gao/stream/ss.java
rename to demo/src/main/java/io/gao/stream/yy.java
index c1cc4e0..9ff0e45 100644
--- a/demo/src/main/java/io/gao/stream/ss.java
:
简要的增改行数统计
--stat,仅显示简要的增改行数统计
git log --stat
结果:行数变化 一增一减(1 file changed, 1 insertion(+), 1 deletion(-))
commit d435e30993b0431a507c88233aef6e96dcebf878 (HEAD -> master)
Author: 高建强 <gaojianqiang.gjq@alibaba-inc.com>
Date: Tue Dec 7 16:43:11 2021 +0800
ss
demo/src/main/java/io/gao/stream/{ss.java => yy.java} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
commit 1ab46677d0cde984e0d27692510319401924320f
Author: 高建强 <gaojianqiang.gjq@alibaba-inc.com>
Date: Tue Dec 7 16:40:08 2021 +0800
:
日志展示格式
--pretty 指定使用完全不同于默认格式的方式展示提交历史
比如用 oneline 将每个提交放在一行显示,这在提交数很大时非常有用
git log --pretty=oneline
结果:
d435e30993b0431a507c88233aef6e96dcebf878 (HEAD -> master) ss
1ab46677d0cde984e0d27692510319401924320f ss
a13487b3d91112722573980e01cc8f64ec741dc9 ss
da25908184d04322d05c7a55d2bea1498cdb4ed5 第一次提交
(END)
出了 oneline还有short,full 和 fuller 可以使用
git log --pretty=oneline
git log --pretty=short
git log --pretty=full
git log --pretty=fuller
git log 的其他用法
-p 按补丁格式显示每个更新之间的差异。
--stat 显示每次更新的文件修改统计信息。
--shortstat 只显示 --stat 中最后的行数修改添加移除统计。
--name-only 仅在提交信息后显示已修改的文件清单。
--name-status 显示新增、修改、删除的文件清单。
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。
--graph 显示 ASCII 图形表示的分支合并历史。
--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。
15. Git撤销
取消已经暂存的文件
把文件1取消暂存
git reset HEAD 文件1
把刚刚暂存的所有文件,取消暂存
git reset HEAD .
取消修改
注:只要没有commit就可以回到修改之前的状态
取消对 s2.java 文件的修改
git restore demo/src/main/java/io/gao/stream/s2.java
取消对所有文件的修改
git restore .
使用git reset 命令,后面的参数可以选择:
| 参数 | 意义 |
|---|---|
| --soft | 不删除工作空间的改动代码 ,撤销commit,不撤销git add file |
| --hard | 删除工作空间的改动代码,撤销commit且撤销add |
git reset --hard HEAD~1
HEAD~1表示撤销最后一次commit,同理HEAD~2表示撤销最后两次commit。
git撤销到指定版本commit,后面的全部不要了
git reset --hard 470c95a1fc106a0aa282df0b7bb20c3920dd9a96
删除Git仓库中的上一次提交
git revert HEAD
git reflog 对于恢复项目历史是一个超棒的资源。你可以恢复*几乎* 任何东西 — 任何你 commit 过的东西 — 只要通过 reflog。
你可能已经熟悉了 git log 命令,它会显示 commit 的列表。 git reflog 也是类似的,不过它显示的是一个 HEAD
-
它涉及的只是 HEAD的改变。在你切换分支、用git commit进行提交、以及用git reset撤销 commit 时,HEAD会改变,但当你用git checkout -- <bad filename>撤销时(正如我们在前面讲到的情况),HEAD 并不会改变 — 如前所述,这些修改从来没有被提交过,因此 reflog 也无法帮助我们恢复它们。 -
git reflog不会永远保持。Git 会定期清理那些 “用不到的” 对象。不要指望几个月前的提交还一直躺在那里。 -
你的
reflog就是你的,只是你的。你不能用git reflog来恢复另一个开发者没有 push 过的 commit。
16. Git远程仓库
查看远程仓库名称
可以用 git remote 命令,它会列出每个远程库的简短名字
git remote
结果
origin
查看远程仓库地址
git remote -v
结果
origin https://www.baidu.com (fetch)
origin https://www.github.cn (push)
添加远程仓库
git remote add test https://gitee.com/gaohh001126/test.git
git remote add [shortname] [url]
[shortname] :自己指定的简短的仓库名称
[url] : 远超仓库地址
从远程仓库抓取数据
git fetch [remote-name]
例如
git fetch test
推送数据到远程仓库
Git push 远程仓库名称 分支名称
git push test test/develop
结果
➜ study git:(develop) git push test test/develop
总共 0(差异 0),复用 0(差异 0),包复用 0
remote: Powered by GITEE.COM [GNK-6.2]
To https://gitee.com/gaohh001126/test.git
* [new reference] test/develop -> test/develop
查看远程仓库信息
git remote show [remote-name] 查看某个远程仓库的详细信息
git remote show test
结果
➜ study git:(develop) git remote show test
* 远程 test
获取地址:https://gitee.com/gaohh001126/test.git
推送地址:https://gitee.com/gaohh001126/test.git
HEAD 分支:master
远程分支:
develop 已跟踪
master 已跟踪
为 'git push' 配置的本地引用:
develop 推送至 develop (最新)
master 推送至 master (最新)
远程仓库的删除和重命名
重命名
Git 中可以用 git remote rename 命令修改某个远程仓库的简短名称
git remote rename 当前名称 修改后的名称
git remote rename test origin
删除远程仓库
碰到远端仓库服务器迁移,或者原来的克隆镜像不再使用,又或者某个参与者不再贡献代码,那么需要移除对应的远端仓库,可以运行 git remote rm 命令
git remote rm test
17. 打标签
同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签。人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做
列出现有标签
git tag
新建标签
Git 使用的标签有两种类型:轻量级的(lightweight)和含附注的(annotated)。轻量
级标签就像是个不会变化的分支,实际上它就是个指向特定提交对象的引用。而含附注标
签,实际上是存储在仓库中的一个独立对象,它有自身的校验和信息,包含着标签的名字,
电子邮件地址和日期,以及标签说明,标签本身也允许使用 GNU Privacy Guard (GPG) 来
签署或验证。一般我们都建议使用含附注型的标签,以便保留相关信息;当然,如果只是临
时性加注标签,或者不需要旁注额外信息,用轻量级标签也没问题。
创建一个含附注的标签
使用 -a
git tag -a v1.0 -m "my version v1.0"
查看标签信息
git show 命令查看相应标签的版本信息,并连同显示打标签时的提交对象
git show v1.0
结果:
tag v1.0
Tagger: 高建强 <gaojianqiang.gjq@alibaba-inc.com>
Date: Tue Dec 7 19:44:02 2021 +0800
my version v1.0
commit f6194a4f05c1093e0632f073fc08e9c6d280b048 (HEAD -> develop, tag: v1.0, origin/develop)
Author: 高建强 <gaojianqiang.gjq@alibaba-inc.com>
Date: Tue Dec 7 19:22:17 2021 +0800
添加年龄
diff --git a/demo/src/main/java/io/gao/stream/s2.java b/demo/src/main/java/io/gao/stream/s2.java
index 42cadae..8df04c7 100644
--- a/demo/src/main/java/io/gao/stream/s2.java
+++ b/demo/src/main/java/io/gao/stream/s2.java
@@ -9,4 +9,5 @@ package io.gao.stream;
创建签署标签
git tag -s v1.0 -m "xxxxx"
创建轻量级标签
git tag v1.0
只要在打标签的时候跟上对应提交对象的校验和(或前几位字符)
标签推送到远程仓库
默认情况下,git push 并不会把标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。其命令格式如同推送分支,运行 git push origin [tagname]
git push origin --tags
18. Git config
Git 并不会推断你输入的几个字符将会是哪条命令,不过如果想偷懒,少敲几个命令的字
符,可以用 git config 为命令设置别名。
git config --global alias.last 'log -1 HEAD'
通过上方命令设置自己的git快捷键
git last
Git 分支
针,作者和相关附属信息,以及一定数量(也可能没有)指向该提交对象直接祖先的指针
当使用 git commit 新建一个提交对象前,Git 会先计算每一个子目录(本例中就是项目根目录)的校验和,然后在 Git 仓库中将这些目录保存为树(tree)对象。之后 Git 创建的提交对象,除了包含相关提交信息以外,还包含着指向这个树对象(项目根目录)的指针,如此它就可以在将来需要的时候,重现此次快照的内容了。现在,Git 仓库中有五个对象:三个表示文件快照内容的 blob 对象;一个记录着目录树内容及其中各个文件对应 blob 对象索引的 tree 对象;以及一个包含指向 tree 对象(根43第3章 Git 分支 Scott Chacon Pro Git目录)的索引和其他提交信息元数据的 commit 对象

作些修改后再次提交,那么这次的提交对象会包含一个指向上次提交对象的指针

Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。Git会使用 master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次提交对象的 master 分支,它在每次提交的时候都会自动向前移动。

创建新分支
git branch push
创建分支之后结构会类似于这样,两个分支都指向最后一提交。

Git 是如何知道你当前在哪个分支上工作的呢?其实答案也很简单,它保存着一个名为 HEAD 的特别指针
HEAD指向的就是当前使用的分支

切换分支
git checkout [目标分支]
eg:
git checkout develop
切换到新分支之后HEAD指针就指向你所在的分支了

这样我么就可以在不同的分支进行操作了,在时机成熟的时候把他们合并到一起

创建分支快捷命令
创建并切换到 issue21 分支
git checkout -b issue21
这个命令相当于两个命令
git branch issue21
git checkout issue21
删除分支
git branch -d issue21
分支合并
场景:当我们切出一个分支去修改一些内容,现在修改完毕了,要把我们切出去的分支和主分支合并。怎么做
1. 先在切出去的分支上进行保存,存到暂存区
git commit -a -m "修改说明"
2. 存入暂存区后切换到主分支
git checkout master
3. 把切出去的分支的代码合并到主分支上面
git merge issue21
合并冲突
如果顺利的话完成上面的操作之后我们就可以把自己分支上面的内容合并到主分支上面了。
为什么说如果顺利的话呢?因为有很大的几率出现意外情况。
在你切出 issue21分支去修改代码的时候,你的同事在master分支上也修改了代码。或者同事也切出去一个分支修改代码。
如果你们恰好修改的同一个文件 比如 s2.java 这个类,那么修改完之后进行上面的操作合并的时候是一定会出现冲突的
➜ study git:(develop) git merge issue
自动合并 demo/src/main/java/io/gao/stream/s2.java
冲突(内容):合并冲突于 demo/src/main/java/io/gao/stream/s2.java
自动合并失败,修正冲突然后提交修正的结果。
这个时候需要解决冲突
此时 使用 git status 可以看到提示有冲突产生
➜ study git:(develop) ✗ git status
位于分支 develop
您有尚未合并的路径。
(解决冲突并运行 "git commit")
(使用 "git merge --abort" 终止合并)
未合并的路径:
(使用 "git add <文件>..." 标记解决方案)
双方修改: demo/src/main/java/io/gao/stream/s2.java
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
代码中也会出现
public String printInfo(String name,Integer age){
String person = "小明";
String s = name+age;
<<<<<<< HEAD
return "小明"+age+"岁了";
=======
return person+age;
>>>>>>> issue
}
}
可以看到 ======= 隔开的上半部分,是 HEAD(即 master 分支,在运行 merge 命令时检出的分支)中的内容,下半部分是在issue 分支中的内容
第一种解决冲突的方法
这个也是我见过有史以来最蠢的一种方法
public String printInfo(String name,Integer age){
String person = "小明";
String s = name+age;
<<<<<<< HEAD
return "小明"+age+"岁了";
=======
return person+age;
>>>>>>> issue
}
}
在上面这段代码处理冲突,选择保留的部分,删除掉多余的 <<<<<<< HEAD ======= >>>>>>> issue
public String printInfo(String name,Integer age){
String person = "小明";
String s = name+age;
return "小明"+age+"岁了";
}
}
然后放入暂存区,再push到远程分支
git commit -a -m "解决冲突"
git push origin develop
第二种解决冲突的方法
在idea中切换主分支

选择刚刚迁出来的分支,选择合并到当前分支

工作中是怎样合并分支并且解决冲突的
切到主分支
在主分支拉取最新代码
切到自己的分支
点击IDEA右下角的GIt工具现在主分支
点击合并到当前分支 merge into current branch
在页面中解决冲突,选择自己想要保留的部分
切换到主分支
git merge 自己的分支
衍合(合并分支的另一种方法)
把一个分支整合到另一个分支的办法有两种:merge(合并) 和 rebase(衍合)
你会看到开发进程分叉到两个不同分支,又各自提交了更新

最容易的整合分支的方法是 merge 命令,它会把两个分支最新的快照(C3和 C4)以及二者最新的共同祖先(C2)进行三方合并

三方合并结束之后提交得到c5分支
git rebase --onto master server client
$ git checkout master
$ git merge client
Git技巧
在你工作的同时,Git 在后台的工作之一就是保存一份引用日志——一份记录最近几个月你的 HEAD 和分支引用的日志。你可以使用 git reflog 来查看引用日志
git reflog
交互式暂存
如果你运行git add时加上-i或者--interactive选项,Git就进入了一个交互式的shell模式,显示一些类似于下面的信息
git add -i
储藏
经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较
杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工
作,否则以后你无法回到这个工作点。解决这个问题的办法就是git stash命令。
git stash
当处理完一些事情,切回到自己的分支想要继续工作
git stash list
展示自己暂存的东西
git stash apply
可以重新应用你刚刚实施的储藏
如果你想应用更早的储藏,你可以通过名字指定它
git stash apply stash@{0}
要移除它,你可以运行git stash drop,加上你希望移除的储藏的名字:
git stash drop stash@{0}
git stash pop 来重新应用储藏,同时立刻将其从堆栈中移走
git stash pop
git stash apply 不会从堆栈中移走储藏
Git config
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com


浙公网安备 33010602011771号