分享一下个人总结的git语法、使用规范以及碰到问题的debug(自己感觉能覆盖90%的内容)。
觉得有用的话,帮忙点个赞吧_(手动加狗头)
$ git branch # 查看当前版本库所有分支
$ git branch <name> # 创建新的分支
$ git checkout <name> or git switch <name> # 切换分支
$ git checkout -b <name> or git switch -c <name> # 创建并切换至新的分支
$ git merge <name> # 将name分支合并至当前分支
$ git log --oneline --graph # 查看具体log信息
$ git branch -d <name> # 删除分支
$ git tag <tag_name> # 为当前的commit创建新的标签
$ git tag -d <tag_name> # 删除标签
Generate SSH Key by ssh-keygen
usage: ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile]
[-m format] [-N new_passphrase] [-O option]
[-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]
[-w provider] [-Z cipher]
if the following error occur
git@github.com: Permission denied (publickey). fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
Solution
$ ssh-keygen -t rsa -C hongfeiniu1@gmail.com
$ ssh-add ~/.ssh/id_rsa # add ssh key to ssh-agent
Could not open a connection to your authentication agent.
# linux
$ eval "$(ssh-agent -s)" # option 1
$ eval "ssh-agent" # option 2
# windows
PS D:\code> get-service ssh*
PS D:\code> Set-Service -Name ssh-agent -StartupType Manual
PS D:\code> Start-Service ssh-agent
# 查看ssh-add添加成功
PS D:\code> ssh-add -l
Status Name DisplayName
------ ---- -----------
Stopped ssh-agent OpenSSH Authentication Agent
$ ssh-copy-id -i ~/.ssh/tatu-key-ecdsa user@host
$ ssh -vT git@github.com # auth the key
A通过ssh登陆B时提示 Host key verification failed.
A的known_hosts文件中记录的B的公钥1 与 连接时B传过来的公钥2不匹配。
A通过ssh首次连接到B,B会将公钥1(host key)传递给A,A将公钥1存入known_hosts文件中,以后A再连接B时,B依然会传递给A一个公钥2,OpenSSH会核对公钥,通过对比公钥1与公钥2 是否相同来进行简单的验证,如果公钥不同,OpenSSH会发出警告, 避免你受到DNS Hijack之类的攻击。。
known_hosts字符串格式:ip 公钥
192.168.44.241 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCHtSvSwuK5F32cxU+5zYtZ/EzHPAO5rTvKgvqldLLKp8sM8uB2RivcZT+U+kcl38F73qRK7iGmUUq7ZXMJE0ag=
Solution
方法一:删除A的known_hosts文件中记录的B的公钥(手动进行,不适用于自动化部署情形)
方法二:修改配置文件,在ssh登陆时不通过known_hosts文件进行验证(安全性有所降低),修改完需重启机器
$ vi ~/.ssh/config #编辑配置文件
添加以下两行内容:
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
$ ssh-keygen -R 你要访问的IP地址 #update the ssh key? 测试
Change the Connection to SSH
$ git remote set-url origin git@github.com:Hongfei-Niu/Note.git
# for Windows
$ git remote set-url origin https://github.com:Hongfei-Niu/Note.git
$ git config pull.rebase false
Git global setup
git config --global user.name "牛鸿飞"
git config --global user.email "niuhongfei@wuzhi-ai.com"
Create a new repository
git clone git@gitlab.wuzhi-ai.com:niuhongfei/playbook_standardization.git
cd playbook_standardization
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
Push an existing folder
cd existing_folder
git init
git remote add origin git@gitlab.wuzhi-ai.com:niuhongfei/playbook_standardization.git
git add .
git commit -m "Initial commit"
git push -u origin master
Push an existing Git repository
cd existing_repo
git remote rename origin old-origin
git remote add origin git@gitlab.wuzhi-ai.com:niuhongfei/playbook_standardization.git
git push -u origin --all
git push -u origin --tags
git mv old_filename new_filename
git add folder
如果我们不小心提交了一版我们不满意的代码,并且给它推送到服务器了,在代码没被merge之前我们希望再修改一版满意的,而如果我们不想在服务器上abondon,那么我们怎么做呢?
追加提交,它可以在不增加一个新的commit-id的情况下将新修改的代码追加到前一次的commit-id中
$ git commit --amend
如果master发生变动:
Format of the commit message: #
<type>(<scope>): <subject>
<body>
<footer>
First line cannot be longer than 70 characters, second line is always blank and other lines should be wrapped at 80 characters.
Allowed <type> values:
For more info about message body, see:
Closed issues should be listed on a separate line in the footer prefixed with “Closes” keyword like this:
Closes #234
or in case of multiple issues:
Closes #123, #245, #992
All breaking changes have to be mentioned in footer with the description of the change, justification and migration notes.
BREAKING CHANGE:
`port-runner` command line option has changed to `runner-port`, so that it is
consistent with the configuration file syntax.
To migrate your project, change all the commands, where you use `--port-runner`
to `--runner-port`.
Capitalized, short (50 chars or less) summary
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase can get confused if you run the
two together.
Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug." This convention matches up with commit messages generated
by commands like git merge and git revert.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, followed by a
single space, with blank lines in between, but conventions vary here
- Use a hanging indent
当前的工作区和上一次commit的版本库
$ git diff
当前的暂存区和上一个commit
$ git diff --cached
当前暂且区和工作区
$ git diff HEAD
不同分支的文件的文件
$ git diff <branchA> <branchB> <filePath>
# 注意有个点“.”
git rm -r --cached .
git add -A
git commit -m "chore<.gitignore>: update .gitignore"
补充一下 .gitignore 的匹配规则:
#以此开头的行为注释行
.a #过滤所有 .a 结尾的文件
/a/ #过滤根目录下的 a 文件夹下的所有文件
/a/do.c #过滤指定文件 /a/do.c
!lib.a #从过滤的文件中排除 lib.a
!/a/b #从过滤的文件中排除 根目录下a目录下的b文件
!.c #从过滤的文件中排除所有.c文件
/TODO #仅仅过滤项目根目录下的 TODO 文件,不包括subdir/TODO
build/ #过滤 build/目录下的所有文件
# * 用来匹配零个或多个字符,如*.[oa]忽略所有以".o"或".a"结尾,*~忽略所有以~结尾的文件(这种文件通常被许多编辑器标记为临时文件);
# [] 用来匹配括号内的任一字符,如[abc],也可以在括号内加连接符,如[0-9]匹配0至9的数;
# ? 用来匹配单个字符。
doc/*.txt #过滤doc下所有txt文件,但不包括子目录下的txt文件,如doc/server/arch.txt
doc/**/*.txt # 会忽略掉 doc/ 里面所有的txt文件,包括子目录下的(**/ 从 Git 1.8.2 之后开始支持 **/ 匹配模式,表示递归匹配子目录下的文件)
调试.gitignore文件
有时候,确定为什么要忽略特定文件可能会很困难,尤其是当您使用多个.gitignore文件或复杂格式时。这是git check-ignore命令的用处,告诉git显示匹配模式的详细信息。
例如,要检查为什么忽略www/yarn.lock文件,可以运行:
git check-ignore -v www/yarn.lock
# 输出显示gitignore文件的路径,匹配行的编号和实际模式。
www/.gitignore:31:/yarn.lock www/yarn.lock
该命令还接受多个文件名作为参数,并且文件不必存在于您的工作树中。
显示所有被忽略的文件
带有–ignored选项的git status命令显示所有被忽略文件的列表:
git status --ignored
当需要拉取远端文件,但又不想提交正在修改的文件时,可以使用git stash 命令将当前的工作区保存(藏匿)起来,等pull 完后再还原。
此功能类似于实现了 ‘局部拉取更新’ 。
命令如下:
git stash //暂存修改工作区
git pull //拉取远端文件
git stash list
git stash pop stash@{0} //将工作区还原
注:如果还原工作区的文件与pull 下来的文件有冲突,要手动修改冲突
git stash pop
但如果使用 git stash pop 后有冲突时,如何撤销?
Git remote -v
Git remote add upstream <git link>
Git remote -v
Git fetch upstream
Git checkout master
Git merge upstream/master
Git push origin master
本地或者自己单独的仓库使用reset 或者revert都可以
涉及到远程仓库(公用仓库)时,不要使用reset,而使用revert回滚
git revert 撤销某次操作
git revert [–[no-]edit] [-n] [-m parent-number] [-s] [-S[]] …
–edit or --no-edit是否弹出commit message窗口
**-n **是 --no-commit的缩写
-m parent-number 存在merge是,指定父系分支号?这个还不怎么懂,暂时略过。
假设master分支上的提交记录如下:
A->B->C->D
目前HEAD指向commit D,我们要将代码revert到B提交时的状态
# Method 1
$ git revert C D # 会生成2个新的commit分别覆盖C、D的提交
# Method 2
$ git revert -n C D # 不会生成新的提交,但是回滚变动会作为修改变动添加到了索引区,可以直接调用git commit保存或者git revert --conitnue弹出commit页面
# Method 3
$ git revert -n C..D
$ git revert C..D # 类似方法1,revert从C到D之间的提交,假设中间还有很多提交时可以用这种
其他操作
$ git revert HEAD # 撤销前一次 commit
$ git revert HEAD^ # 撤销前前一次 commit
$ git revert HEAD~10 # 将head指向上10次的commit。
$ git revert <commit id> #(比如:fa042ce57ebbe5bb9c8db709f719cec2c58ee7ff)撤销指定的版本,撤销也会作为一次提交进行保存。
git revert是提交一个新的版本,将需要revert的版本的内容再反向修改回去,版本会递增,不影响之前提交的内容
git reset [–soft | --mixed [-N] | --hard | --merge | --keep] [-q] []
参数可以选择:
假设master分支上的提交记录如下:
A->B->C->D
目前HEAD指向commit D,我们要将代码回退到B提交时的状态
# 方法1
$ git reset --soft B # 这个时候可以发现,C,D两次提交做的修改依然存在,并且在索引区内,这个时候如果直接调用git commit ,可以生成一个新的提交E,E包含C、D两次提 交的修改。
# 方法2
$ git reset --mixed B # 二者是一样的
$ git reset B # 这个时候可以发现,C,D两次提交做的修改依然存在,但是不在索引区内,记如果需要重新提交,则需要先调用git add。
# 方法3
$ git reset --hard B # 和--soft、--mixed不同的是,C,D两次提交做的修改以及D以后做的一些没有提交的修改都不复存在
--merge说明
这个参数使用的有一定的前提,需要保证没有添加到索引区的修改文件在新旧两个HEAD直接的提交中没有过修改。如果下面命令调用成功
$ git reset --merge B
则会保留没有添加到索引区的修改。即,假设commit C 和 commit D都只修改了a.txt,而在D后我们又修改了b.txt,但是没有调用git add b.txt保存修改到索引区,则调用git reset --merge B 成功后,原来对b.txt做的修改还会存在,但是C、D提交中的修改将会回滚消失
--keep说明
和--merge有一些类似。使用成功的前提是:在D后有本地修改的文件在C、D两次提交中没有修改过,即C、D两次提交中没有它的修改记录。
假设我们在D后修改了a.txt文件,而且C、D两次提交中我们都没有修改a.txt文件,这样我们调用
git reset --keep B
可以成功,并且a.txt文件中的修改依然会保留。
说明:变基操作。
假设如下:
master分支提交历史为:A->B->C->D
你后面发现commit C和D有些问题,需要做一些变动,比如
- 将C、D两次提交合并成一次提交 squash D //将D合并到C提交 或者用fixup D,但是这样会丢弃D的提交message
- 删除D提交 drop D //删除D
- 修改D提交的message reword D//修改D提交的message,等等。
则可以调用
git rebase -i B
然后会弹出编辑窗口,相应的做修改即可。也就是变更修改pick、reword、squash、fixup、drop等命令。
pick:保留这份commit。
reword: 保留这份commit,但是会重新编辑commit信息
squash : 这份commit的内容虽然会保留,但是会合并到先前的commit中。
drop: 移除这份commit的内容
等等
假设origin/master 分支上的提交历史为 A->B->C->D;
- 你在本地新添加了一个提交E,则master为A->B->C->D->E。
- 此时队友新推送一个提交N到origin/master,则origin/master 分支上提交历史为A->B->C->D->N。
- 如果你在本地采用merge的方式,则提交历史会在分叉变成A->B->C-D->(E,N)->M(表示Merge后的新提交)。
而才有rebase方式的话
$ git fetch origin master # 更新代码
$ git rebase origin/master # 变基操作
# 则本地master提交历史可能变成A->B->C->D->N->E不会存在分叉。
假设如下:
- master分支提交历史为:A->B->C
- server分支提交历史为:A->B->D->E
- client分支提交历史为:A->B->D->F
$ git rebase [startpoint] [endpoint] --onto [branchName] # 将当前分支的commits 放到目标分支,HEAD anchor还在原先的commit上
$ git checkout <branchName>
$ git reset --hard <new commit id> # 并把HEAD anchor移到最新的commit上
# 新花样
$ git rebase --onto master server client
这样会取出client分支,找出处于client分支和server分支的共同祖先之后的修改,然后把他们在master分支上重演一遍
这样client分支会变成A->B->C->F,注意server和client共同拥有的D提交记录在client里消失了
git pull --rebase
- git pull = git fetch && git merge
- git pull --rebase = git fetch && git rebase
完整流程
$ git rebase --continue
# 如果有冲突, 解决冲突
# after solving the conflicts
$ git add .
# 不需要commit
$ git rebase --continue
$ git push
Explanation 1
To be specific, it equals to:
$ git fetch origin
$ git rebase --onto origin/foo e(middle commit) foo
Explanation 2
Suppose you have two commits in local branch:
D---E master
/
A---B---C---F origin/master
After “git pull”, will be:
D--------E
/ \
A---B---C---F----G master, origin/master
After “git pull --rebase”, there will be no merge point G. Note that D and E become different commits:
A---B---C---F---D'---E' master, origin/master
rename branch
Step 1. 本地分支重命名(还没有推送到远程)
git branch -m oldName newName
Step 2. 远程分支重命名 (已经推送远程-假设本地分支和远程对应分支名称相同)
# a. 重命名远程分支对应的本地分支
git branch -m oldName newName
# b. 删除远程分支
git push --delete origin oldName
# c. 上传新命名的本地分支
git push origin newName
# d.把修改后的本地分支与远程分支关联
git branch --set-upstream-to origin/newName
Recover the remote branch
思路:找到分支id,本地重新创建该分支,推送到远程
Step 1: 找到分支commitId
很多种方法
git reflog
git log
或者gitlab or github界面Project Activity里找到操作ID
Step 2: 本地重新创建分支,推送到远程
生成READ.md的目录: gh-md-toc or “Markdown All in One” Plugin in VSCode
gh-md-toc
will automatically be available in the PATH
$ wget https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc
$ chmod a+x gh-md-toc
$ curl https://raw.githubusercontent.com/ekalinin/github-markdown-toc/master/gh-md-toc -o gh-md-toc
$ chmod a+x gh-md-toc
$ basher install ekalinin/github-markdown-toc
STDIN
Here’s an example of TOC creating for markdown from STDIN:
$ cat ~/projects/Dockerfile.vim/README.md | ./gh-md-toc -
Local files
Here’s an example of TOC creating for a local README.md:
$ ./gh-md-toc ~/projects/Dockerfile.vim/README.md
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge (the default strategy)
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
When the ip is changed and relevant host get clean, the password would pop up as: "git@github.com’s password: ". May caused by ssh.
研究一下github验证机制
(Git TroubleShooting)[https://docs.github.com/en/authentication/troubleshooting-ssh/error-permission-denied-publickey]
Git 大小写不敏感,修改目录名大小写失败
$ git config core.ignorecase false
Solution
Cause
git mv CyberSecurity/password.md CyberSecurity/ldap.md
Error
fatal: not under version control, source=CyberSecurity/password.md, destination=CyberSecurity/ldap.md
Solution1
Most easiest way to solve this issue is to first we need to add the file first and then we need to rename the file
$ git add file-name
$ git mv current-file-name new-file-name
and then your problem will be solve.
Caused by Case Sensitive difference between Git and Windows Shell
Another quirk that left me frustrated is if you're using the command line, it will use your current path to git mv the file. So if you have a file in C:\Git\MyRepo\MyFolder\MyFile.txt
If you do:
c:
cd git
cd myrepo
cd myfolder
dir
It will work fine, you'll see your file. But if you type git mv MyFile.txt MyFile2.txt you will get an error because git can't find Myfile.txt.
The reason is that it's looking at your current path, which is c:\git\myrepo\myfolder\
But git is case sensitive. So you have to go back and type
c:
cd Git
cd MyRepo
cd MyFolder
If you then type git mv it will work fine.
Putting this in as an answer for people like me that found this post while debugging this error message.
edit .git/config
git push不上去的原因在于所push的分支权限为protected,只有项目的管理员或者项目的管理员指派的具有相应权限的人才能进行push,要进行项目的push,有如下两种方法:
1.将所要push的内容所在的分支的protected权限关闭
2.新建其它分支,将项目push到新建的分支上,后期再进行merge
# 新建分支
git branch feature
# 切换分支
git checkout 分支名
# 进行项目上传
git add .
git commit -m "提交的信息"
git remote add origin 远程仓库地址
git push -u origin 分支名
ERROR: Permission to hbxn740150254/BestoneGitHub.git denied to Chenzuohehe. fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository exists.
https://www.jianshu.com/p/12badb7e6c10
域名污染,需要在绕过DNS解析图片链接的域名,在/etc/hosts文件中直接配置ip
xxx.xxx.xxx.xxx raw.githubusercontent.com
xxx.xxx.xxx.xxx githubusercontent.com