Linux命令 git


原文链接: Linux命令 git

[](https://github.com/brigade/overcommit)

高富帅们的Git技巧 - 新闻 - SegmentFault

git 查看某个文件的修改历史

  1. git log -p filename

查看文件的每一个详细的历史修改,如果没有-p选项,只显示提交记录,不显示文件内容修改,git log -p -3 filename 显示最近的3次提交。

  1. git log --pretty=oneline filename

每一行显示一个提交,先显示哈希码,再显示提交说明。

  1. git blame filename

查看文件的每一行是哪个提交最后修改的。

git找到两个分支的分叉点

https://stackoverflow.com/questions/1527234/finding-a-branch-point-with-git#4991675
git rev-list --boundary develop...master | grep "^-" | cut -c2-
git rev-list ^develop --first-parent master

默认使用 rebase

git config --global branch.autosetuprebase always

git代理设置方法解决

git config --global https.proxy http://127.0.0.1:1080
git config --global https.proxy https://127.0.0.1:1080
git config --global --unset http.proxy
git config --global --unset https.proxy
npm config delete proxy
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'

对比指定目录与上次提交之间的差别(或者更准确的 说是在当前分支)。

git diff HEAD -- ./lib

恢复指定目录文件

git checkout HEAD~ application/admin/

把hello.rb从HEAD中签出并且把它恢复成未修改时的样子.

git checkout -- hello.rb

                                     remote repo

working staging local repo
工作区 暂存区 本地仓库

    add          ->           commit    ->

<- rm --cached <- reset --soft
<- checkout

当我们需要删除暂存区或分支上的文件, 同时工作区也不需要这个文件了, 可以使用
git rm file_path 同时删除 staging staging
当我们需要删除暂存区或分支上的文件, 但本地又需要使用, 只是不希望这个文件被版本控制, 可以使用
git rm --cached file_path 仅删除staging 保留staging

git rm -r --cached .

git清理大文件

使用git branch-filter来遍历git history tree, 可以永久删除history中的大文件,达到让.git文件瘦身的目的。

下面给出步骤(以下步骤非常危险,操作需谨慎!别把公司删没了哈哈)

  1. 首先找出git中前五大的文件:

git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -5

  1. 根据文件id找出对应的文件名:

git rev-list --objects --all | grep 8f10eff91bb6aa2de1f5d096ee2e1687b0eab007

  1. 彻底删除大文件
    sh git filter-branch --index-filter 'git rm --cached --ignore-unmatch <your-file-name>' rm -rf .git/refs/original/ git reflog expire --expire=now --all git fsck --full --unreachable git repack -A -d git gc --aggressive --prune=now git push --force [remote] master
    首先,里面最重要的两条命令是 git filter-branch 和 gc, filter-branch 真正在清理,但是只运行它也是没用的,需要再删除备份的文件,重新打包之类的,最后的gc命令,

用来收集产生的垃圾,最终清除大文件。

一步到位,再看看你的.git文件,有没有大吃一惊呢!

3.5 git给远程库添加多个url地址

场合:你可能想要把你的本地的git库,既push到github上,又push到开源中国的Git@OSC上或者coding net上,怎么解决呢?有人可能会用两个甚至多个远程库,即再添加一个远程库git remote add origin2;这个方法很低效,因为你要git push 两次才能完成push到两个库。
解答原理:git的一个远程库可以对应多个地址。
基本命令:

在本地仓库创建一个指向远程仓库url的链接别名name,可以任意命名:git remote add name url1 (name可以为origin、both等等自定义的名字)

  1. 增加第1个远程库地址:git remote set-url --add --push origin url1 #remote url1 必须添加 否则无法推送到真正的主库
  2. 再增加第2个远程库地址:git remote set-url --add --push origin url2
  3. 删除url链接别名name:git remote rm name (常见的为origin)
    显示当前所有远程库的详细信息,显示格式为:远程库名字 url连接(类型),命令:git remote -v
    查看config文件,里面可以看到添加的地址,位于当前工程.git/config中,可使用命令:git config -e
    推送时只需要执行命令:git push name master,其中name就是url的链接别名,master是推送的分支,要保证几个推送仓库的分支命名是一样的。

3.6 查看改动的内容
改动的内容如果commit的话,可使用:
git log -n 2 --stat :查看最后两次改动过的文件
git log -n 1 -p :查看最后一次提交更改的细节
使用git diff来查看改动内容,其中HEAD代表commit版本,Index代表staged版本
git diff:比较工作目录(Working tree)和暂存区域快照(index)之间的差异,也就是修改之后还没有暂存起来的变化内容。
git diff --cached:查看已经暂存起来的文件(staged)和上次提交时的快照之间(HEAD)的差异
git diff --staged:显示的是下一次commit时会提交到HEAD的内容
git diff HEAD:查看workspace和local repository的差别
git diff b1 b2 或 git diff b1..b2:将b1和b2分支上的最新提交做diff
git diff test:查看当前目录和test分支的差别
git diff HEAD^ HEAD:比较上次提交commit和上上次提交
git_diff_pic

3.7 分支重命名
步骤如下:

把test1分支重命名为test2:git branch -m test1 test2
删除远程分支test1:git push --delete origin test1
将本地分支test2推到远程:git push origin test2

清理 .git 缩减目录大小

git gc

Git合并branch上的指定文件

git checkout -p develop A.h //不切换 branch,把 develop 上的A.h更新到当前分支
git checkout develop .drone* //去掉-p参数,新增 .drone.yml .drone.yml.sig 文件

允许空提交

git commit --allow-empty -m "Initializing gh-pages branch"

lfs

Apt/deb repos: curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
Yum/rpm repos: curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.rpm.sh | sudo bash
sudo apt-get install git-lfs

github Emoji表情包

http://www.webpagefx.com/tools/emoji-cheat-sheet/

关闭git pull 弹出的merge 信息

git reset --hard origin/master

[core]
    mergeoptions = --no-edit

git config --global core.mergeoptions --no-edit

git clone文件太大时怎样处理

clone的时候,可以指定深度,如下,为1即表示只克隆最近一次commit.
git clone --depth 1 git@github.com:/

subtree 在主分支管理子项目

1、初始化子项目Subtree
通过
cd P1项目的路径
git subtree add --prefix=用来放S项目的相对路径 git地址 xxx分支
这样的命令,把S项目(我们姑且叫他S项目)的代码下载到--prefix所指定的目录——我们姑且叫他S目录把,并在P1项目里自动产生一个commit(就是把S目录的内容提交到P1项目里)。
对于P2项目也做同样的操作
2、像往常一样更新代码
大家在P1项目里各种提交commit,其中有些commit会涉及到S目录的更改,正如前面提到的,这是没任何关系的,大家也不会感受到有任何不一样。
3、提交更改到子项目的Git服务器
关键的地方来了:
当维护这个S项目 Subtree 的人希望把最近这段时间对S目录的更改提交到S项目的 Git 服务器上时,他执行一段类似于这样的命令:
cd P1项目的路径
git subtree push --prefix=S项目的路径 git地址 xxx分支
Git 会遍历所有的commit,从中找出针对S目录的更改,然后把这些更改记录提交到S项目的Git服务器上
4、更新子项目新的代码到父项目
OK,现在S项目有大量的新代码了,P2项目也想使用这些新代码,维护P2这个Subtree的人只要执行:
git subtree pull --prefix=S项目的路径 git地址 xxx分支
这样就可以将P2项目里S项目目录里的内容更新为S项目xxx分支的最新代码了。

Git多账号切换

有时候会遇到需要使用多个git账号的情况,手动切换是在过于麻烦。
于是就有了一下的解决方案:
首先,切换到ssh的key目录下:
cd ~/.ssh
然后使用ssh-keygen命令创建一个新的SSH key:
ssh-keygen -t rsa -C "sencond@mail.com" -f id_rsa_second
其中id_rsa_second表示保存的key的名称,可以自定义,命令执行之后会在.ssh目录里出现两个文件其中id_rsa_second.pub表示公钥。后面会用到。
由于默认情况下,每次进行SSH连接时默认发送本地钥匙(默认为~/.ssh/id_rsa)。所以之前生成的id_rsa_second在默认情况下是没有被用到的。
这时就需要在~/.ssh 目录创建config文件,该文件用于配置钥匙对应的服务器信息。具体语法如下:
Host 别名

HostName        主机名
Port            端口
User            用户名
IdentityFile    密钥文件的路径

其中Host别名自己任意给出,能方便记忆就行。给出一个示例配置以供参考:

Default github user(first@mail.com)

Host github.com

 HostName github.com
 User git
 IdentityFile ~/.ssh/id_rsa

second user(second@mail.com)

Host github-second

 HostName github.com
 User git
 IdentityFile ~/.ssh/id_rsa_second

配置完成之后,在连接非默认账号需要修改一下远程库的地址,
如本来的远程库地址为git@github:sencond/test.git
现在就需要改为git@github-second:sencond/test.git。
而且通过 ssh + 别名就能登录远程库
注意:

切换账号的时候要修改相应的配置文件
 git config --global user.name 用户名
 git config --global user.email second@email.com
在远程端添加前面生成的id_rsa_second.pub的公钥到远程库里。
使用对应的ssh key密码。

git 分支合并时如何忽略某个文件 .drone.yml

https://stackoverflow.com/questions/332528/is-it-possible-to-exclude-specific-commits-when-doing-a-git-merge/3970442#3970442
首先git merge大致是这样的逻辑(可以去看英文原文):git在merge分支时,有一个默认的merge驱动,这个驱动会去检查每个文件的每一行,如果按照一定规则发现两个分支的同一个文件有不同,那么认为两个分支都对这个文件做了修改,会merge两个文件,此时有可能产生冲突;那么如果我们自定义一个merge驱动,在里面定义一些不会被检查的文件,那git就会直接跳过这些文件,因此就不会merge,而我们自定义的这个merge驱动就是 ours。

1:创建我们的自定义merge driver:

git config --global merge.ours.driver true

这样选定了ours驱动,至于为什么不选择其它驱动,可以详看官方文档。
不管在A分支怎么修改a.js,B分支合并A分支时,B分支的a.js保持原样,就需要 定义merge driver

注意:如果仅仅设置了.gitattributes中a.js merge=ours,他们还是会合并,只是有冲突时以当前分支的为准.

2:在要被merge的分支上创建 .gitattributes 文件,并且在文件中置顶不merge的文件名:

echo '.drone.yml merge=ours' >> .gitattributes
git add .gitattributes
git commit -m 'chore: Preserve .drone.yml during merges'

.gitattributes文件内容如下:

.drone.yml merge=ours

3:在合并的时候选择驱动要选择ours,这样就可以了。
如果是命令行合并:

git checkout master
`git merge -s ours newbranch`

git 分支合并时如何忽略某个文件

我通过使用git merge命令与’–no-commit’选项来解决这个问题,然后明确删除暂存文件并忽略对文件的更改。
例如:说我想忽略对 .drone.yml 的任何更改我继续如下:

git merge --no-ff --no-commit develop
git reset HEAD .drone.yml
git checkout -- .drone.yml
git commit -m "merged "

你可以把语句2& 3在for循环中,如果你有一个文件列表要跳过。

`