常用git命令,欢迎大家参考!
1. git介绍
git与svn一样都是基于仓库来管理代码的,不过git的仓库在客户端和服务端都是存在的,我们通常都是在本地进行代码commit,然后再提交到远端服务器仓库的;而svn的话,差不多相当于大家一群人都在仓库远端的一个仓库,在本地进行commit,马上主动推送到远端仓库,灵活性稍差点;
2. 在本地生成一个仓库(一般就是一个项目等)
A:本地初始化一个文件夹为一个仓库,让git把这个文件夹当作一个仓库进行操作;
- git init
- git remote add origin git@github.com:Hinsteny/Test.git
为刚刚初始化的仓库添加一个远程仓库联系,这样我们就能把本地的代码提交到远程了哈
B:直接在本地clone一个远程仓库,即把远程仓库的所有受管理文件复制到本地,然后进入仓库根目录就可以进行相关操作,比如修改(编写自己的代码),推送(更新自己的代码到远程服务器);
- git clone git@github.com:Hinsteny/Test.git
- cd Test
现在就能在修改clone下的仓库(Test里面)下面的文件了。
3. 对本地仓库内容进行修改
A:git在本地修改时是基于branch进行操作的,每个branch可以保留不一样的副本;
- 新建分支: git branch branch_name
- 查看本地所有分支列表: git branch -a
- 切换到要进行操作的分支: git checkout branch_name
- 跳过创建分支的步骤,直接创建(clone当前分支)并切换到新分支: git checkout -b branch_name
- 跳过创建分支的步骤,直接创建(以指定的tag为分支版本)并切换到新分支: git checkout -b branch_name tag_name
B:在当前分支上,对受管理的文本文件做一些修改,然后就可以commit到当前分支上;
- 先把修改添加到缓存: git add file_url_name (只是添加一个文件,git add . 命令可以把当前分支上的所有修改添加到缓存)
- 把已经添加到缓存的内容进行commit: git commit -m “commit_content”
- 此时就可以把当前分支的内容进行推送或者检出打包,合并等操作了。
4. 提交本地代码到远程仓库
把本地的[local_branch]上的内容更新到[remote_name]仓库的[remote_brnach]上面;
git push [remote_name] [local_branch]:[remote_brnach]
remote_name:某个远端的remote地址在本地对应的名称;
local_branch:本地仓库的某个分支名称;
remote_brnach:远端仓库的某个分支名称;
注:上面命令可以简写为 “git push”,默认为 “oringin, local/master, origin/master”, 设置本地的某个分支为本地的master分支的命令是:git push --set-upstream oringin/master
5. 推送内容和拉取远程的内容到本地
-
git push [remote_name] [local_branch]:[remote_brnach]
-
git pull [remote_name] [remote_brnach]:[local_branch]
-
git fetch [remote_name] [remote_brnach]:[local_branch]
6. 本地修改的相关操作
- 取消对文件的修改。放弃未提交的修改,还原到最后一次commit后的状态。
git checkout -- [file-path-name]
- 还原被加入缓存状态文件的状态。即,撤销之前的add file-path-name 操作
git reset -- [file-path-name] (git reset HEAD -- [file-path-name])
- 还原所有被加入缓存状态文件的状态。即,撤销之前的add . 操作
git reset (git reset HEAD)
- 撤销本地某个文件的修改
git checkout -- filename
- 撤销所有本地文件的修改
git checkout -- . (git checkout .)
- 当前工作区内容不变,但是暂存区会回退到上一次提交之前
git reset head^
- 回退某个文件的版本到上一个版本
git reset HEAD^ [file-path-name]
- 向前回退到第X个版本
git reset --soft HEAD~3
- 将本地的状态回退到和远程的某个分支一样
git reset --hard origin/master
- 回退到某个具体的版本
git reset version-number
7. 回滚本地提交
- git reset --hard commit-id: 强制把当前分支回滚到所指定的commit记录;
git reset --hard HEAD~3: 将最近3次的提交回滚;
- git reset --soft head^: 将最近1次的提交软回滚;
git reset --soft head~3:将最近3次的提交软回滚;
注: hard方式的回滚会直接抹消被回滚的commit的修改;而soft方式的话,只会把当前分支的commit指向回滚到的位置,然后被回滚的所有commit的修改会依然保存在本地,以git缓存的方式存在;
8. 合并冲突
- git merge [branch_name] :把当前分支与目标分支合并,把当前分支的内容与目标分支的内容进行对比列出区别,手动解决冲突后进行commit,所以最后会有一个“Merge branch”的commit哈
解决完冲突后,在commi历史中会多一个merge的commit,里面可能包含一些冲突解决时代码的取舍痕迹。
- git rebase [branch_name] :把当前分支与目标分支合并,把当前分支超前的commit追加到目标分支的commit之后
解决完冲突后,在commit历史上看不出有合并的痕迹。
9. 打包本地的commit生成相关commit文件以便直接传送补丁
- git format-patch -[number] :number表示打包的补丁从最后一次commit向前数一共生成多少个commit的补丁。执行完命令后,会在当前仓库的根目录下生成对应的补丁文件(文件名称一般会包含一部分commit的描述内容,方便区分)。
git format-patch –[number] commit-id :某次提交之前的所有patch
git format-patch -M master :打包当前分支所有超前master的commit
git format-patch -s commit-id :某次提交以后的所有patch
- git apply --stat patch_url :检查一个补丁文件的状态,会看到这个补丁里面包含哪些修改的内容概括
- git apply --check patch_url :检查一个补丁文件是否可以成功打补丁到当前分支上面(可以的话,就可以直接应用补丁成功;否则进行应用的补丁过程中就需要解决冲突哈)
- git am patch_url :把一个补丁文件里面的修改应用到当前分支上面哈
10. 合并时,如果有冲突如何解决?
- 在使用 “git rebase” 命令时,当不能顺利的进行合并时,那就是有冲突了,这个时候就定位到两个分支有冲突的公共地方,主动的进行取舍保留,确定好要保存的版本快照后,回到命令行,执行 "git add ."把解决分支产生的修改添加到缓存中,然后再执行 “git rebase --continue”,完美解决冲突,哈哈
- 在使用 “git am” 命令时,当不能顺利的把补丁文件应用到当前分支上时,那就是有冲突了,这个时候就定位到有冲突的公共地方,主动的进行取舍保留,确定好要保存的版本快照后,回到命令行,执行 "git add ."把解决分支产生的修改添加到缓存中,然后再执行 “git am --continue”,就这么解决冲突,哈哈
11. git库所在的文件夹(即.git所在的文件夹)中的文件包含四种状态。
- untracked:未跟踪,此文件在文件夹中,但并没有加入git库,不参与版本控制。 通过”git add”,”git commit”可将它置入版本管理库。
- unmodify:文件已经库中,未修改,即版本库中的文件快照内容与文件夹中完全一致。这种类型的文件有两个去处,如果它被修改,而成为modified。如果使用”git rm”移出版本库,则成为untracked文件。
- modified:文件已修改,仅仅是修改,并没有进行其它操作。这个文件也有两个去处,通过”git add”可进入暂存(staged)状态,使用”git checkout”则丢弃修改,返因到unmodify状态。这个checkout很好理解,就是取出库中文件,覆盖当前文件吧。
- staged:暂存状态。执得”git commit”则将修改同步到库中,这时库中的文件与本地文件又一致了,于是文件是unmodify状态。执行”git reset HEAD filenam”取消暂存,文件状态变为modified。
注:如果你是用在wins下面,适用powershell打开git shell命令行,那这几种状态可以随时看到的,“untracked"一般是红色的”+number"(数字表示有多少个文件未被加入版本库),“unmodify"就是正常状态,没什么特别显示,“modified"一般是红色的”~number”(数字表示有多少个文件被修改了),"staged"一般是绿色的(表示对应的文件已经被加入了git暂存中);
12. 撤销本地工作目录中当前分支上的修改
- git reset --hard origin/master :强制回滚到master分支的最后一次commit,这种方法就是找一个历史节点进行强制状态回滚。这个操作会清除"修改,删除"两种更改,但不会清除"添加"这种修改;(并不提倡这种方式)
- git checkout – . :这个操作会清除当前分支上的"修改,删除"两种更改,但不会清除"添加"这种修改;这个命令也可以是"git checkout – file_url",针对性的对某个文件进行修改撤销,但是它依然不能对一个新增加的文件进行撤销,猜测可能是因为新加文件还没有被纳入git版本管理中去,没有历史快照给它做参考进行回滚撤销(git对工作目录中未加入版本管理的文件好像没有删除的命令,这里可以用系统的删除命令进行删除,rm);
- git reset HEAD file_url :将对应已经加入git暂存的文件恢复到modified状态;
13. git tag(标签),可以在一定的时期对commit设置历史关键点,常常用来进行标志版本发布点.
- git tag (-l): 显示当前版本库的所有标签列表.
- git tag tag_name: 截止当前分支最后一个commit创建一个新的tag.
- git tag -a tag_name -m 'tag_commit′: 创建一个带备注信息的tag.
- git push --tags: 把本地的所有标签推送到远程服务器上面.
- git show tag_name: 显示一个tag一些相关信息.
- git tag -d tag_name: 删除本地的一个tag.
- git push origin :refs/tags/tag_name: 删除远端的一个tag.
14. git log,查看历史提交的commit内容.
- git log : 显示当前分支的历史commit内容.
- git log --stat : 显示当前分支的历史commit内容和每次commit对应修改了哪些文件.
15. git stash,强大的当前工作状态暂存方式.
- git stash save “name” : 把当前工作目录的所有修改添加到一个stash记录里面.
- git stash pop “stash-index” : 把某个index的stash记录加载(弹出)到当前工作目录(同时stash列表里移除对应的记录)。
- git stash apply “name” : 把某个index的stash记录加载(应用)到当前工作目录(同时stash列表里依旧保留对应的记录)。
- git stash drop “stash-index” : 移除掉某个index对应的stash记录。
应用场景:比如自己正在开发一个功能,突然接到修改一个紧急bug的任务, 就可以先暂存自己的工作状态, 修改完bug后, 返回到自己的工作进度.
16. 版本管理中对文件的忽略
- gitignore 文件 : 在项目的根目录下的.gitignore为全局的文件过滤设置,即会影响本地和远程。
- exclude 文件: 位于 {项目路径}/.git/info/exclude. 该文件主要用于忽略不想加入版本控制的文件而又不影响远端。只影响本机的文件忽略配置。
- 命令忽略 : 只对指定路径文件有效(对文件夹无效)
//设置某个文件暂时不参与版本管理(但是远程修改它更新到本地可能会有冲突需要解决)
git update-index --assume-unchanged <file-path>
//设置某个文件恢复参与版本管理
git update-index --no-assume-unchanged <file-path>
17. git clone big repositories 很慢或者发生异常终止情况如何处理
如果我们通过 git clone https://xxxx
克隆一个比较大的仓库时, 有可能就会发生异常终止的情况, 类似
.............
remote: Compressing objects: 100% (3256/3256), done.
fatal: read error: Invalid argument, 255.05 MiB | 1.35 MiB/s
fatal: early EOF
fatal: index-pack failed
解决方法如下:
# 关闭压缩设置
git config --global core.compression 0
# 浅层次目录clone
git clone --depth 1 <repo_URI>
# 获取所有历史记录
git fetch --unshallow
# 获取所有内容
git pull --all
18. 查看内容列表信息
如果我们要看一下某个git-project工程目录下的文件树列表信息,就可以用这些命令,可以看到文件的读写执行权限,类型,签名等信息
# 列出当前目录所有文件信息
git ls-tree HEAD
# 列出当前目录所有文件信息及子目录文件信息
git ls-tree -r HEAD
# 列出当前目录所有文件夹信息
git ls-tree -d HEAD
# 列出指定目录下的所有文件信息
git ls-tree -r HEAD:sub-dir
19. commit 摘取
把其他分支中的某个commit记录摘取到当前分支
#
git cherry-pick <commit id>
20. commit 合并
有时我们在本地开发时会按照小功能分别进行多次commit, 最后在往远端push时想把多个commit合并成一个commit其中包含一个完整或者大的功能开发;
- 在本地分支(test_rebase_commit_merge)上进行多个commit
git log
------------------
# Commit D
# Commit C
# Commit B
# Commit A
- 使用git rebase -i命令进行commit合并
# 修改当前分支最近的三个commit
git rebase -i HEAD~3
-------------------
pick 3c0d9fd # Commit B
pick 3793e85 # Commit C
pick 79513ca # Commit D
# Rebase 44edb14..79513ca onto 44edb14 (3 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 <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
......
- 修改最上面三个commit 的处理方式
pick 3c0d9fd # Commit B
squash 3793e85 # Commit C
squash 79513ca # Commit D
# Rebase 44edb14..79513ca onto 44edb14 (3 commands)
......
修改后:wq
保存退出
- 然后进入写一个新commit-content的界面
# This is a combination of 3 commits.
# This is the 1st commit message:
# Commit B
# This is the commit message #2:
# Commit C
# This is the commit message #3:
# Commit D
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Mon Dec 2 15:32:11 2019 +0800
#
# interactive rebase in progress; onto 44edb14
上面说了让我们重写写个合并后的commit-content, 不能以#开头(#开头的是注释), 我们就到内容的最下面新起一行, 写个Merge commit content
, 最后:wq
保存退出
- 查看合并后的commit内容
Merge commit content
# Commit A
21. 修改git commit的username和email
我们既可以给一个git项目配置user.name和email, 也可以设置本地全局的user.name和email, 项目的配置优先于全局的, 默认项目配置来着全局;
- 配置全局的user.name和email
git config --global user.name 'Hinsteny'
git config --global user.email 'hinsteny@gmai.com'
- 配置一个项目的user.name和email
git config user.name 'Hinsteny'
git config user.email 'hinsteny@gmai.com'
- 修改一个项目中历史commit中的user.name和email
在项目根目录中创建一个change.sh文件, 内容如下
#!/bin/sh
git filter-branch --env-filter '
OLD_EMAIL="hinsteny@qq.com"
CORRECT_NAME="Hinsteny"
CORRECT_EMAIL="hinsteny@gmai.com"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
- 如果脚本执行失败,可以先执行下面的命令,然后再执行脚本
git filter-branch -f --index-filter 'git rm --cached --ignore-unmatch Rakefile' HEAD
- 本地执行git log, 可以看到已经修改过来了, 接下来push到远端仓库
git push origin -f
22. 查看指定两个分支上commit的差异
上面案例19中我们使用cherry-pick摘取指定commit记录到当前分支upstream, 有时候我们想将指定分支中的某几个commit(a, b, c)合并进当前分支,但是又忘记了已经合并了哪些又有哪些没合并,这时就可以比较下,轻松查看合并情况
git cherry -v master feature_user | grep +
23. 删除历史指定commit
有时候我们需要删除历史的某个commit内容,不需要那个commit包含的修改了,但是在它之前、之后的内容我们还是需要的,如下
历史commit有a, b, c, d…,我们需要删除b和c
git rebase -i [d-id]93c98006ac396611a753766e0ce7fa2fd4420b0a
进行commit编辑页面
pick [a-id]
pick [b-id]
pick [c-id]
按键’i’,进行编辑
pick [a-id]
drop [b-id]
drop [c-id]
按键’esc’,输入’!wq’保存变更并退出编辑;
再次查看git commit log,发现只剩a,d,而b,c已经不在了;
git log
PS: 待续