以下所有用法以 ubuntu 为例
0.git 是什么?
1. 安装 git
1.1 安装 git 客户端
sudo apt-get install git
1.2. 配置用户和邮箱
$git config --global user.name "Your Name"
$git config --global user.email "email@example.com"
每个机器都必须带 name 和 email,作为提交者的唯一凭证;
git config 命令的 --global 参数,表示这台机器上的所有 Git 仓库都会使用这个地址
git config --list // 查看当前配置
1.3 配置默认编辑器为 vim
ubuntu 上默认时 nano, 我还是习惯用 vi;
git config --global core.editor vim
2. 本地仓库基本用法
2.1 创建一个本地 repo
$mkdir project;cd project
$git init // 初始化一个本地空仓库
2.2 提交一个 commit
(1) 添加文件
$git add readme.txt
git add: 把一个文件添加到 git 系统中,或者说添加到 git 缓存中;git rm: 把版本库的文件或目录删除
git mv: 移动或重命名文件;
提交包括新建,或者修改的文件 (直接编辑);
(2)git status 命令
查看仓库当前的状态
git status // 查看哪些文件被修改
git status:
跟踪三类命令
traced, 已跟踪的文件,已经在版本库里;
ignored,被忽略的文件,通常临时文件;
untracked, 未跟踪的文件,通常新建文件属于这一类;
(3) 查看本地文件修改内容
git diff
查看两个指定版本的内容差异:
git log
git diff vxxx1 vxxx2
(4)add 修改到暂存区
git add . // 添加当前目录及其子目录下所有改动;git add .../xxx // 可以 add 指定文件
(5) 提交修改
add 所有改动到暂存区后,提交到本地仓库;
$git commit -m "wrote a readme file"
git commit -s // 社区规范,自动添加 Signed-off-by:
2.3 修改最近一次提交
可以将修改文件,或者注释,提交到最近一个 commit(commit-ID 保持不变);
git diff
git add .
git commit --amend
重新修改最近一次提交,如果文件内容为改变,那么只改变 log 信息
2.4 如何修改最近一个提交的作者
git commit --amend --author="leon <leon@qq.com>"
2.5 查看历史版本 log 记录
git log
git log --pretty=oneline //log 简短信息
git log --oneline
git log --author=Linus --oneline // 按行查看某人的所有提交
git log --patch-with-stat // 查看当前 patch 提交差异,包括文件名和内容
git show xxx_id // 查看指定 commit_id 的提交差异
其他用法:
git log xxxx
xxx 可以是一下:绝对提交名:40 位 16 进制哈希值
符号引用:HEAD 指向最近的提交
相对提交名字:master 表示 master 分支头,master^ 表示 master 分支倒数第二个 commit
范围:符号.. 表示一个范围,master~12..master~10: 表示 master 分支上倒数第 11 和 10 个提交;git log --pretty=short master~5..master~3
git log --pretty=short master~5..master~3 --stat
查看分支合并情况
git log --graph --pretty=oneline --abbrev-commit
6. 回退到上一个版本
git reset --hard HEAD^
上上个:HEAD^^
上 N 个:HEAD~n
恢复到指定版本
git reset --soft xxxx // 将 HEAD 引用指向给定的提交,索引和工作内容不变, 只回退 commit, 本地修改保持;如还要再提交,直接 commit 即可;git reset --mixed xxxx : 索引内容跟着改变,工作目录内容不变;git reset --hard xxxx // 索引和工作内容都改变, 放弃所有修改,回退到 XXX 版本
git reflog:列举历史回退记录,可以查询版本 ID 号
回退到远程 remote 同步
git reset --hard origin/master
7. 查看工作区和版本库区别
git diff 显示在缓存中或未在缓存中的改动
git diff HEAD -- readme.txt
git diff: 显示尚未缓存的改动:git diff --cached: 查看已经缓存的改动
git diff HEAD 查看所有的改动
git diff --stat 显示摘要
8. 撤销修改
1) 撤销工作区修改
git checkout -- readme.txt
2) 撤销暂存区修改
git reset HEAD readme.txt // 撤销指定文件 readme.txt 的 add
git reset HEAD // 撤销所有 add
3) 若没提交到远程版本库,撤销本次提交
git reset // 版本回退
9. 删除文件
1) 删除
git rm test.txt
git commit -m "remove test.txt"
2) 误删: 恢复最新版本
git checkout -- test.txt // "--" 不能省,否则变成了切换到另一个分支
3) 从版本库里删掉某文件的版本管理,但是不删除本地文件
git rm -r --cached -n xx.txt //- n 只是打印,不真正执行
git rm -r --cached xx.txt// 执行 rm 命令,本地文件会保留
10. 建立一个服务器仓库
server 端:
mkdir git_test.git
sudo chmod 777 -R git_test.git/
git_test.git/
git --bare init // 初始化一个服务端的空仓库
client 端:
git init
git add cpu.txt
git status
git commit -s
git log
ifconfig
git remote add origin ssh://leon@192.168.0.128:/opt/git_test.git
git remote remove origin // 删除远程 remote
git remote -v
git push origin master // 当前分支 master 推送到远程仓库 origin,同名分支
cd ..
git clone ssh://192.168.0.122:/opt/git_test.git git_test2
cd git_test2/
11. 分支操作
1). 查看分支
git branch
git branch -a
git show-branch -a // 查看详细分支,和提交信息
2) 创建分支
git branch <name>
git branch xx/dev 创建分层的分支
3) 切换分支
git checkout <name>
4) 创建 + 切换分支
git checkout -b <name>
5) 删除分支
git branch -D <name>
// 删除远程分支
git push origin --delete remoteBranchName
6) 合并某分支到当前分支
git merge <name> //Fast-forward 模式合并,就是直接把 master 指向 dev 当前提交
git merge xxx // 两个分支按提交时间顺序合并
git rebase xxx // 站在另一个分支的肩膀上
按时间 abcdefg
a-b-c-e
\d-f-g
qgit --all
图形化查看 git commit
用途:当需要合并别人修改,考虑用 merge
当你的开发工作或者提交的补丁需要基于某个分支之上,用 rebase 命令,比如向内核社区提交补丁;
用 --no-ff 强制禁用 Fast forward 模式
开发中,一般 master 分支用来发布版本,而开发工作在各自的 dev 分支开发并提交,只有稳定版本才合并到 master
git merge --no-ff -m "merge with no-ff" dev
这样普通模式合并后,就有历史分支信息,能看出来曾经做过合并;
12 解决冲突
1) merge 方式
git merge dev
git merge debug
Auto-merging dev.c
CONFLICT (content): Merge conflict in dev.c
Automatic merge failed; fix conflicts and then commit the result.
leon@leon:~/lab03_merge$ vim
vim dev.c // 手动修改
git status
git add .
git merge --continue // 继续 merge
2)rebase 方式
git rebase dev
$ git rebase debug
First, rewinding head to replay your work on top of it...
Applying: malloc 100bytes
Using index info to reconstruct a base tree...
M dev.c
Falling back to patching base and 3-way merge...
Auto-merging dev.c
CONFLICT (content): Merge conflict in dev.c
error: Failed to merge in the changes.
Patch failed at 0001 malloc 100bytes
hint: Use 'git am --show-current-patch' to see the failed patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
leon@leon:~/lab03_rebase$
git am --show-current-patch
vim dev.c // 手动修改
git add dev.c
git rebase --continue // 继续 rebase
git log
3)patch 方式
git format-patch -1
生成 0001-dev-malloc-100-bytes.patch
git checkout master
git am 0001-dev-malloc-100-bytes.patch
查看 patch
vim .git/rebase-apply/0001
git apply .git/rebase-apply/0001 --reject // 生成改动文件
// 手动修改
vim dev.c dev.c.rej
git add dev.c
继续 patch
git am --resolved
git log
13. git revert 把某个提交给撤销
git revert master~3
a-b-c-d-e-f-g master
-->
a-b-c-d-e-f-g-d' master
14.git cherry-pick 摘草莓
从某个 git tree 或分支上摘取一个 commit 到当前分支
把 dev 的 f 节点 commit 摘到 master 分支上
a-b-c-d-e-f-g-h dev
\v-w-x-y-z master
git checkout master
git cherry-pick dev~2
a-b-c-d-e-f-g-h dev
\v-w-x-y-z-f' master
15 管理远程仓库
git remote 命令
git remote -v // 查看远程仓库地址
git remote add name_xxx 添加远程仓库地址
git remote show xxx // 查看远程仓库的所有信息
git remote update // 抓取远程版本库中所有可用更新到本地仓库里面
git fetch xxx // 抓取远程 xx 版本库到本地
添加和删除远程分支
添加:
git push 远程主机名 本地分支名:远程分支名
git push orgin master
git push origin master:dev // 若 dev 不存在,就新建一个远程 dev 分支
删除:
git push 远程主机名 : 远程分支名
git push 远程主机名 -d 远程分支名
拉取远程指定分支:
git pull 远程仓库门 远程分支名
git pull linux linux-5.13
Git push 命令用于从将本地的分支版本上传到远程并合并。
命令格式如下:
git push < 远程主机名 > < 本地分支名 >:< 远程分支名 >
// 如果本地分支名与远程分支名相同,则可以省略冒号:git push < 远程主机名 > < 本地分支名 >
实例
以下命令将本地的 master 分支推送到 origin 主机的 master 分支。
$ git push origin master
相等于:
$ git push origin master:master
如果本地版本与远程版本有差异,但又要强制推送可以使用 --force 参数:
git push --force origin master
推送标签到远程仓库
默认情况下,git push 并不会把 tag 标签传送到远端服务器上,只有通过显式命令才能分享标签到远端仓库。
1.push 单个 tag,命令格式为:
git push origin [tagname]
$ git push origin tag_20170908 // 将本地 tag_20170908 的 tag 推送到远端服务器
2.push 所有 tag,命令格式为:
git push [origin] --tags
git push --tags
或
git push origin --tags
git 如何将本地分支同远程分支进行关联
将本地分支同远程分支进行关联,可以分为以下 2 种情形:
情形 1:
本地已经创建了分支 dev(以 dev 为例,下同),而远程没有
可以通过以下 2 种方法在远程创建分支 dev,并与本地分支进行关联:
方法 1:git push -u origin dev
方法 2:git push --set-upstream origin dev
情形 2:远程已经创建了分支 dev, 而本地没有
在本地创建分支并与远程分支进行关联,也有 2 种方法:
方法 1 分为两步:
step1: 先将远程分支 pull 到本地 git pull origin dev
step2: 再在本地创建分支并与之关联,又有 2 种方法
(1)git checkout -b dev origin/dev
(2)git checkout -b dev --track origin/dev #可以简写为 git checkout --track origin/dev
方法 2:可以在 pull 远程分支的同时,创建本地分支并与之进行关联
git pull origin dev:dev------- 两个 dev 分别表示远程分支名:本地分支名
12.github 远程仓库
1) 创建 SSH Key
cd ~/.ssh
ssh-keygen -t rsa -C "youremail@example.com"
一路回车会生成 id_rsa 和 id_rsa.pub 两个文件
id_rsa 是私钥,id_rsa.pub 是公钥
登陆 github.com,选择 setting/ssh keys/
添加 SSH key
把公钥 id_ira.pub 内容复制过去
2)gitHub 上创建一个仓库,然后把本地仓库与之关联,进行同步
git remote add origin git@github.com:luteresa/testgit.git // 关联一个远程库,远程库名字 origin
git push -u origin master // 推送 master 分支所有内容到远程 origin 仓库的 master 分支
3) 从已经存在的远程仓库克隆
git clone git@github.com:luteresa/gitskills.git
... // 本地代码管理操作
git push -u origin master // 推送到远程仓库
// 加上 "-u" 参数,Git 不但把本地的 master 分支内容推送到远程的 master 分支,还会把它们关联起来,以后推送或者拉取时就可以简化命令;
git push origin master
13. 过滤不需要提交到仓库的文件
在工作区目录下创建.gitignore 文件,提交到仓库则生效
https://github.com/github/gitignore
GitHub 做好了很多文件,可以稍加修改拿来用;
如果文件被.gitignore 过滤掉,但又确实想添加,可以强制添加
git add -f file.txt
或者发现无法提交,可能是.gitignore 写的有问题,可以查询哪个规则写错了
git check-ignore -v file.txt
17.BUG 分支,“储藏”现场
每个 Bug 都可以通过临时分支来修复,修复后合并分支,然后删除临时分支;
比如接到临时 bug 任务 issue-101, 先将工作现场临时“储藏”起来,修复后,再恢复现场
git stash
这是用 git status 查看工作区是干净的,因此可以放心创建临时分支
git checkout -b issue-101
在 issue-101 上修复 bug,提交;
git add;
git commit -m "fix bug 101"
修复完成后,切换到 master 分支,完成合并,删除 issue-101 分支
git checkout master
git merge --no-ff -m "merged bug fix 101" issue-101
git branch -d issue-101
完成后,切换到工作区继续干活
$ git checkout dev
Switched to branch 'dev'
$ git status
# On branch dev
nothing to commit (working directory clean)
工作区是干净的,恢复储藏代码
git stash list
两种方式恢复:
1)git stash apply; // 恢复工作区内容
git stash drop; // 删除 stash 内容
2)git pop // 恢复的同时把 stash 内容删掉
git stash list 查看
可以多次 stash,然后恢复制定 stash
@git stash list
stash@{0}: WIP on dev: 6224937 add merge
git stash apply stash@{0}
18.Feature 分支
添加定制新功能时,为不影响主干代码,可以建立 featurea 分支,完成后合并,最后删除 feature 分支
Feature 分支操作与 BUG 分支类似,当在没有合并之前,if 删除,就会丢失掉修改,如果要强行删除,
git branch -D featrue-branch
19. 多人协作
1). 查看远程库信息,使用
git remote -v;
2) 本地新建的分支如果不推送到远程,对其他人就是不可见的;
3) 从本地推送分支,使用
git push origin branch-name
如果推送失败,先用 git pull 抓取远程的新提交
4) 在本地创建和远程分支对应的分支,使用
git checkout -b branch-name origin/branch-name
本地和远程分支的名称最好一致;
5) 建立本地分支和远程分支的关联,使用
git branch --set-upstream branch-name origin/branch-name
6) 从远程抓取分支,使用 git pull,如果有冲突,要先处理冲突
20. 标签管理
1) 标签与分支类似,是指向 commit 的指针,但是标签不可移动;
2)TAG 就是给个容易记的名字,与原来某个 commit 绑定一定;
3) 默认创建标签给 HEAD,也可以指定一个 commit
git tab v1.0
git log --pretty=oneline --abbrev-commit
git tab v0.9 ea7edc2
git show v0.9
4) 可以指定标签信息
git tag -a v0.1 -m "version 0.1 released" 3628164
5) 可以用 PGP 签名标签
git tag -s
签名采用 PGP 签名,因此,必须首先安装 gpg(GnuPG),如果没有找到 gpg,或者没有 gpg 密钥对
git show
用 PGP 签名的标签是不可伪造的,因为可以验证 PGP 签名。
6) 修改标签,可以删除
git tag -d v0.1
7) 推送标签到远程
git push origin v0.1
一次性推送所有未被推送到远程的标签
git push origin --tags
8) 标签已推送远程,删除方法
git tag -d v0.1 // 本地删除
git push origin :refs/tags/v0.1 // 再 push 远程删除
21. 使用 GitHub
1) 在 GitHub 上,可以任意 Fork 开源仓库;
自己拥有 Fork 后的仓库的读写权限;
可以推送 pull request 给官方仓库来贡献代码;
1)
22. 关联本地仓库与远程仓库
1)git remote add origin http://luteresa@192.168.13.168:10009/r/AF_SAMPLE.git
2)git pull origin master
3)git push -u origin master
23. 本地仓库与多个远程仓库了关联
1) 查询本地仓库的远程关联
~$ git remote -v
origin ssh://admin@192.168.13.168:29418/AF_SAMPLE.git (fetch)
origin ssh://admin@192.168.13.168:29418/AF_SAMPLE.git (push)
2)add 关联新的远程仓库
git remote add s1_3m ssh://admin@192.168.13.168:29418/S1_3M_AF.git
$ git remote -v
origin ssh://admin@192.168.13.168:29418/AF_SAMPLE.git (fetch)
origin ssh://admin@192.168.13.168:29418/AF_SAMPLE.git (push)
s1_3m ssh://admin@192.168.13.168:29418/S1_3M_AF.git (fetch)
s1_3m ssh://admin@192.168.13.168:29418/S1_3M_AF.git (push)
3) 推送远程仓库
git push [远程库名] [本地分支名] : [远程分支名]
git push s1_3m s1_3m
4) 从指定远程仓库 pull
git pull s1_3m s1_3m
24. 查看哪些文件是在版本控制下;
git ls-files
25.git 注释换行
git commit -m '
1.it is a test;
2.linefeed;
'
26. 修改文件名
git mv oldname newname
27. 查询哪些文件在版本控制下
git ls-files
28.fork 之后的本地仓库与原仓库同步;
场景:
在 github,从祖师爷 torvalds 的帐号里,fork 了 linux 的源码;将自己 github 里的 Linux 仓库 clone 到本地供学习研究用;
自己的修改,也会及时提交到 github 仓库,问题来了,一段时间之后,torvalds 的仓库有了很多更新,如何将这些更新同步到个人 github 仓库?
原仓库:https://github.com/torvalds/linux.git
个人仓库:https://github.com/luteresa/linux.git
step1: 在本地仓库添加原仓库为上游代码库
$ git remote -v
origin https://github.com.cnpmjs.org/luteresa/linux.git (fetch)
origin https://github.com.cnpmjs.org/luteresa/linux.git (push)
$git remote add upstream https://github.com/torvalds/linux.git
$ git remote -v
origin https://github.com.cnpmjs.org/luteresa/linux.git (fetch)
origin https://github.com.cnpmjs.org/luteresa/linux.git (push)
upstream https://github.com/torvalds/linux.git (fetch)
upstream https://github.com/torvalds/linux.git (push)
由于众所周知的原因,给 github 加下速,添加 upstream2;leon@pc:~/work/myHub/kernel$ git remote -v
origin https://github.com.cnpmjs.org/luteresa/linux.git (fetch)
origin https://github.com.cnpmjs.org/luteresa/linux.git (push)
upstream https://github.com/torvalds/linux.git (fetch)
upstream https://github.com/torvalds/linux.git (push)
upstream2 https://github.com.cnpmjs.org/torvalds/linux.git (fetch)
upstream2 https://github.com.cnpmjs.org/torvalds/linux.git (push)
step2, 同步上游原仓库修改到本地;
leon@pc:~/work/myHub/kernel$
git fetch upstream2
leon@pc:~/work/myHub/kernel$ git log
commit 8404c9fbc84b741f66cff7d4934a25dd2c344452
Merge: a79cdfb 36f0b35
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date: Wed May 5 13:50:15 2021 -0700
Merge branch 'akpm' (patches from Andrew)
Merge more updates from Andrew Morton:
"The remainder of the main mm/ queue.
143 patches.
可见,本地仓库实际代码尚未同步
查看本地分支:
leon@pc:~/work/myHub/kernel$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/upstream2/master
step3: 合并上游原仓库修改到本地
$ git merge upstream2/master
leon@pc:~/work/myHub/kernel$ git log
commit a050a6d2b7e80ca52b2f4141eaf3420d201b72b3
Merge: 1434a31 f8b61bd
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date: Mon May 24 16:03:24 2021 -1000
可见本地源码已同步到最新
step4: 本地修改推送到 github
git push
git push origin HEAD --force
29git 获取标签对应的版本
git clone 整个仓库后使用,以下命令就可以取得该 tag 对应的代码了
原仓库:
打标签
git tag tag_name xxxx
另外目录:
git clone kernel/ -b tag_name new_dir
但是,这时候 git 可能会提示你当前处于一个“detached HEAD" 状态。
因为 tag 相当于是一个快照,是不能更改它的代码的。
如果要在 tag 代码的基础上做修改,你需要一个分支:
cd new_dir
git checkout -b branch_name tag_name
这样会从 tag 创建一个分支,然后就和普通的 git 操作一样了。