Git

review cheap get diff without merge request

git log --no-merges --first-parent -p git rev-parse origin/master..HEAD^

git bash can’t read windows path variables

append export MSYS_NO_PATHCONV=1 to ~/.bashrc.

how-can-i-start-git-bash-via-windows-terminal-with-environment-variables-set

git checkout Filename too long

git config --system core.longpaths true

filename-too-long-in-git-for-windows

swich pointer to special commit

git update-ref refs/heads/<branch> <commit>

https://stackoverflow.com/a/8206536

open recently modified file

git log --name-only --oneline HEAD^..HEAD | tail -n +2 | xargs -L 1 start

手动同步远程分支

git remote update origin --prune

查看两个分支的merge base

git show-branch --merge-base branch1 branch2(default is current branch)

查看某一行代码的变更历史 view git history of specific line

git log -L '/the line from your file/,+1:path/to/your/file.txt'

view-git-history-of-specific-line

split 方式查看diff结果

git difftool --commit=

https://stackoverflow.com/questions/255202/how-do-i-view-git-diff-output-with-my-preferred-diff-tool-viewer

查看某个commit对应的所有文件(是所有文件,不是变更的文件),即git checkout commit-hash后当前的文件树

git ls-tree -r commit-hash
例如: git ls-tree -r eafeaa

window unix换行符转换

dos2unix <file> find . -iname '*.sh' -exec dos2unix {} + find . -iname '*.sh' -exec dos2unix {} \;

what-does-mean-{}-in-a-linux-command

findcmd.htm

how-to-replace-crlf-with-lf-in-a-single-file

using-git-to-create-an-archive-of-changed-files 生成变更包 导出指定commit中变更的文件

git archive -o update.zip HEAD $(git diff --name-only HEAD^)

using-git-to-create-an-archive-of-changed-files

export-only-modified-and-added-files-with-folder-structure-in-git

git format-patch -1 <sha>
git am < file.patch

generate-a-git-patch-for-a-specific-commit

clone a single branch 克隆某个分支

https://stackoverflow.com/questions/1778088/how-do-i-clone-a-single-branch-in-git

-C指定上下文路径

git -C /path/to/project/root/ command

git log时间显示错位 UTC 时区

git log --date={relative,local,default,iso,rfc}
git config --global log.date local

git-timezone-and-timestamp-format

git status显示乱码问题

输入以下命令解决:

git config --global core.quotepath false

忽略已经提交到版本库中的文件

To untrack a single file that has already been added/initialized to your repository, i.e., stop tracking the file but not delete it from your system use: git rm –cached filename

To untrack every file that is now in your .gitignore:

First commit any outstanding code changes, and then, run this command:

git rm -r --cached .

This removes any changed files from the index(staging area), then just run:

git add .

Commit it:

git commit -m ".gitignore is now working"

To undo git rm –cached filename, use git add filename

参照文章:ignore-files-that-have-already-been-committed-to-a-git-repository

配置Git针对不同的源码库使用不同的账户(ssh授权方式)

参考:How to Work with GitHub and Multiple Accounts

主要原理是利用ssh的config(%USER_HOME%/.ssh/config文件不存在手工创建)文件,针对不同的库使用不同的账户

如果有两个源码库是在同一个域名下,但是需要使用不同的授权账户,有两种方式可以实现

①可以修改本地host,将host映射到ip上进行区分

②直接修改ssh的known_hosts文件,原理与修改host一样

上述两种方法都要求修改同域名下的另一个源码的remote-url为host/known_host配置的新域名

新域名要区别于原域名,即不同的域名指向同一个IP,原域名由DNS解析,新域名有本地host或者known_host解析

查看某行代码的提交历史

git blame -- file_path | grep 'search word' #找到变更行
git log --pretty=short -u -L 115,117:file_path #查看变更历史

参考:retrieve-the-commit-log-for-a-specific-line-in-a-file

从提交中删除指定的文件

前提条件是提交还未push到远端

参考:remove-files-from-git-commit

git reset --soft HEAD^ 
git reset HEAD path/to/unwanted_file
git commit -c ORIG_HEAD

省去每次输入密码的麻烦

git config --global credential.helper store

在git bash中执行上述命令,执行git pull后输入用户名密码即可。用户名密码会以明文形式保存在用户目录下的.git-credentials文件中

cherry-pick某个commit中指定的几个文件变更

git cherry-pick支持指定 -n(–no-commit)参数,该参数表示pick以后不提交,pick以后和git add的结果一样文件在暂存区存放,这时候就可以通过git reset和git checkout配合来选择想要保留的文件了。

示例:

分支dev下的commit1变更文件如下:

file1

file2

现在想要在master分支下只把dev下commit1中的file2文件变更放到master上,全部操作命令如下。

git checkout master #切换至master分支
git cherry-pick -n commit1 #pick提交但是不commit
git reset HEAD file1 #把file1从暂存区还原
git checkout file1 #还原file1
git commit -m '提交file2内容' #提交file2

上述命令就完成把file2的内容放到master下了,该场景适合在临时发布生产内容的时候使用(应该还有其他方案)

解析commit

git rev-parse HEAD #解析出当前分支HEAD指向的commit hash
git rev-parse HEAD^ #解析出当前分支HEAD前一个commit hash
git rev-parse HEAD^^ #解析出当前分支HEAD前两个commit hash

rebase快捷操作

git add -u
git commit --fixup=`git rev-parse HEAD`
git rebase -i --autosquash `git rev-parse HEAD^^`
git add -u
git commit --amend --no-edit

上述命令都可以实现将最新的修改提交后合并到前一个提交上

禁用三方合并弹出的merge message框

git pull时如果产生三方合并,git会弹出确认框让用户可以自己修改自动创建的commit的message

可以通过增加–no-editgit pull --no-edit参数来禁用该弹出框显示。即直接采用自动生成的message

开发人员之间共享本地分支实现方案(windows)

现有开发人员A(devA),开发人员B(devB),其中A本地有个分支branchA,该分支用于代码重构且通过rebase保持和master分支同步

devB如果想在devA的branchA上添加修改项可以通过添加远程跟踪来实现。步骤如下:

  1. devA和devB分别将自己的源码目录共享到局域网,devA的共享目录为://192.168.1.101/shareProject,devB的共享目录为://192.168.1.102/shareProject

  2. devB在本地源码上添加远程跟踪devA的branchA分支git reomte add devA //192.168.1.101/shareProject

  3. devB检出branchA的代码git fetch devA branchA;git checkout devA/branchA

  4. devB基于branchA检出分支branchBgit checkout -b branchB

  5. devB完成开发后提交内容到branchB,假定创建的commit的hash值为:6f91189dd4c345ec974560f1960d7a604d8549da

  6. devA按照步骤1,2,3远程跟踪devB的branchB

  7. devA将分支切换到branchAgit checkout branchA

  8. devA通过cherry-pick将branchB分支上的6f91189dd4c345ec974560f1960d7a604d8549da提交合并到当前分支git cherry-pick 6f91189dd4c345ec974560f1960d7a604d8549da

上述场景适合devA为功能主要开发人员,devB为协助开发的情况,并且devA的branchA不能推送到远端(为了通过rebase与主分支保持同步,所以不能push)的情况

不使用patch,是因为不知道如何保持代码同步,有时间可以研究一下。

合并指定commit到当前分支

git cherry-pick commit列表

commit列表中的提交会被apply到当前分支,但是会产生新的commit hash,可用于临时解决有人误提交内容到主分支。

列出某个提交或者两个提交之间的变更文件列表

git diff-tree --no-commit-id --name-only -r 提交的hash值1 提交的hash值2(可选)

自动重建代码基准(Auto setup rebase)

在其他人已经push过代码到中央服务器,而自己本地也有新的提交需要push,这时候

需要先pull再push,而pull的时候git会自动创建一个新的commit(三方合并)实际上

这个commit是没有任何意义的,而且有时候还会弹出编辑框让手动输入commit的说明,

通过配置autosetuprebase可以将此commit省略。配置如下:

git config --global branch.autosetuprebase alway

关联远程仓库,添加远程仓库

git remote add origin remoteurl

删除远程分支

git push origin --delete branchname #上述命令将删除远程分支branchname

清除未跟踪的文件(新增的文件不需要了,新增的文件不需要加入版本库,多余的文件等等)

git clean -f,可以先使用git clean -n预演一下,看看哪些会被删除掉,或者使用git clean -i进行交互式删除

修改远程仓库地址

git remote set-url origin newurl

查找文件内容的修改人 操作人 改动者 改动人 变更人 变更者 谁修改的 谁改的

git blame filepath | grep 'search content该命令可以查找filepath对应的文件中’search content’是谁修改的

stash使用

git stash #存储当前修改
git stash apply #恢复最近存储的内容
git stash pop #恢复最近存储的内容并删除存储
git stash list #查看stash list
git stash drop #从stash list中删除最近存储的内容

还原文件

git checkout commitHash filename可以将文件还原到commitHash对应的版本

删除配置项

git config --global --unset configname

上述命令删除了配置项configname

rebase的正确使用方式

  1. 先更新主分支

  2. 切换到本地分支并rebase master

  3. 返回主分支merge local_branch

上述方式操作以后主分支的版本线将是一条线

分支

新建并合并分支:git checkout -b branchname

删除分支:git branch -d branchname

日志

重写历史,修改已经commit的log内容

合并提交

合并最近两次提交,在漏提交文件时比较实用,比如先add commit了几个文件,后来发现漏了几个文件,可以 将漏的文件add commit以后,利用下面步骤将两次提交合并

  1. git rebase -i HEAE~2

  2. 在弹出的编辑器中将最后一次的commit message前缀改为squash,保存并退出编辑器

注意一定要修改最后一次的,如果修改前一次的可能会出现错误,出现错误时用

  1. 退出编辑器后会再次自动弹出编辑器,其中显示两次commit合并后的message,编辑改message保存退出即可

Git rebase后本地commit记录丢失问题处理

git rebase失败后可能会导致git log的时候看不到rebase的commit记录,但是可以通过

git reflog命令查看本地所有的commit然后用git reset进行还原,还原之前可以重新创建

个分支进行操作

add的使用技巧

  1. add -u表示只add变更的文件,即只把本次编辑过的文件add到缓存区

  2. 撤销add操作:Git-基础-撤消操作

缓存区

git rm --cached filename(支持*进行多文件匹配)/dir(作用于目录下所有文件)

上述命令是将文件从版本库中删除,通过git status可以看到filename和dir下的文件状态

为untracked

git reset HEAD filename(支持*进行多文件匹配)/dir(作用于目录下所有文件)

上述命令是将文件从stage(缓存区)中删除,通过git status可以看到

filename和dir下的文件状态为unstage

上述是通过实测得出的结论,查看git --help rmgit --help reset均找不到对应的说明

log的使用技巧

查找log

  1. 按时间

    git log --since=开始时间 --until=结束时间

  2. 按commit

    git log commit hash..HEAD

格式化输出

git shortlog --author=liufangjie --since=1.days
git log --author liufangjie --since=1.days --pretty=format:"%h %an %cd %s" --date=iso

log使用技巧

对比差异

git diff 的使用

  1. 对比文件:
git diff commit commit -- filepath
git diff e4cea7 64f237 -- HelloWorld.java
  1. 对比分支差异:git diff branch..branch

  2. 查看变更:git diff ,应该跟git status差不多

  3. 查看add内容:git diff --cached

  4. 查看变更的行数:git diff --stat

git difftool的使用

git difftool -t=vimdiff e4cea7 64f237 -- learn.txt

Git的权限控制

Gitolite 构建 Git 服务器

服务器上的 Git - Gitolite

强制覆盖远端内容

git push branch_name --force

强制覆盖本地内容

git fetch --all
git reset --hard origin/branch_name

Git服务器搭建

搭建服务器ssh环境

参考文章:

git服务器搭建

Gitolite构建Git服务器

环境:ubuntu

  1. 安装openssh

    sudo apt-get install openssh-server

    如果提示没有源,需要在etc/apt/source.list中添加源

    参照文章:ubuntu 安装 openssh-server

    # Archive.ubuntu.com 欧洲,此为官方源,推荐使用 ,PING=500

    deb http://archive.ubuntu.com/ubuntu/ feisty main restricted universe multiverse

    deb http://archive.ubuntu.com/ubuntu/ feisty-security main restricted universe multiverse

    deb http://archive.ubuntu.com/ubuntu/ feisty-updates main restricted universe multiverse

    deb http://archive.ubuntu.com/ubuntu/ feisty-proposed main restricted universe multiverse

    deb http://archive.ubuntu.com/ubuntu/ feisty-backports main restricted universe multiverse

    deb-src http://archive.ubuntu.com/ubuntu/ feisty main restricted universe multiverse

    deb-src http://archive.ubuntu.com/ubuntu/ feisty-security main restricted universe multiverse

    deb-src http://archive.ubuntu.com/ubuntu/ feisty-updates main restricted universe multiverse

    deb-src http://archive.ubuntu.com/ubuntu/ feisty-proposed main restricted universe multiverse

    deb-src http://archive.ubuntu.com/ubuntu/ feisty-backports main restricted universe multiverse

    deb http://archive.ubuntu.org.cn/ubuntu-cn/ feisty main restricted universe multiverse

    添加后使用如下命令更新源

    sudo apt-get update

    更新完成后再执行安装命令

    检查ssh是否启动

    ps -e | grep ssh

    看到sshd进程说明server启动成功

    启动ssh

    sudo /etc/init.d/ssh start

  2. 创建git用户

    sudo adduser git

    带管理员权限:

    sudo adduser --system --shell /bin/bash --gecos 'Git SCM' --group git

  3. 切换到git用户

    su git

  4. 安装git

    sudo apt-get install git-core

  5. 创建git仓库

    git init --bare repo.git

    此命令需要在git用户的home目录下执行

    添加环境变量

    export PATH=/home/git/bin:$PATH

winows上拷贝公钥到git服务器

使用git bash执行命令,请到window的用户主目录下的.ssh目录下执行如下命令:

cat id_rsa.pub | ssh git@192.168.1.140 "cat >> ~/.ssh/authorized_keys"

如果服务器上没有.ssh目录,命令修改为:

cat id_rsa.pub | ssh git@192.168.1.140 "mkdir ~/.ssh; cat >> ~/.ssh/authorized_keys"

192.168.1.140为git服务器,git为git服务器的用户

修改用户密码:

当前用户passwd

修改用户密码:sudo passwd user

删除账户git:sudo userdel git

删除git的home目录:sudo rm -r -d git

ssh登录server

window上安装ssh client

下载: curl -O http://ncu.dl.sourceforge.net/project/sshwindows/OpenSSH%20for%20Windows%20-%20Release/3.8p1-1%2020040709%20Build/setupssh381-20040709.zip

上述命令需要在git bash下执行,文件会下载到当前目录

centos6 minimal安装后网络配置

虚拟机设置网络连接为桥接模式,并且选择复制物理网络连接

参考文章:centos minimal 网络配置

主要修改

/etc/sysconfig/network-scripts/ifcfg-eth0

ONBOOT=”yes”

MM_Controlled=”no”

BOOTPROTO=”dhcp”

dhcp表示自动获取

修改配置以后重启网络:#service network restart

gitolite安装

服务器端

环境:centos root用户 服务器地址192.168.1.102

  1. 创建git账户

    useradd -r -m -c 'Git SCM' -U git

    -r创建系统用户

    -m自动创建home目录

    -c说明

    -U创建同名组

  2. 获取gitolite

    切换到git用户并进入主目录

    su git

    cd $HOME

    git clone git://github.com/sitaramc/gitolite

  3. 配置安装环境

    mkdir /home/bin

    export PATH=/home/bin:$PATH

    上述命令创建了bin目录,并添加bin目录到系统path中

  4. 安装gitolite

    gitolite/install -ln

    上述名及完成gitolite的安装

  5. 到客户端将客户端公钥发送到服务器

    进入客户端存放公钥的目录

    cat id_rsa.pub | ssh git@192.168.1.102 "cat >> myAdminName.pub"

  6. 到服务端继续进行安装

    gitolite setup -pk $HOME/myAdminName.pub

    上述命令

    1. 将客户端的公钥myAdminName.pub设置为gitolite的管理账户

    2. 创建repositories目录

    3. 在上述目录下创建两个rep,分别为gitolite-admin和testing

    gitolite-admin即为权限管理的目录,testing是测试目录

  7. 到客户端clone gitolite-admin项目

    git clone git@192.168.0.102:gitolite-admin

    进入到gitolite-admin中可以看到有两个目录

    conf,keydir

gitolite使用

  1. 创建新的repo

    修改gitolite-admin/conf/gitolite.conf

    添加repo声明内容

    repo mynewrepo

    也可以在已经存在的repo声明语句后面增加,按照语法要求,以空格分开就可以如

    repo testing mynewrepo

    将gitolite.config push到服务端git add/commit/push

  2. 重命名repo

    一定要注意操作顺序

    1. 先到服务端重命名repo的名字mv mynewrepo renamerepo

    2. 修改gitolite.conf然后add commit push

打造没有分叉的master版本线

  1. master分支由专人维护(熟悉git的操作,特别是merge rebase操作等)

  2. 创建dev分支供开发人员使用

  3. 开发人员在本地不直接编辑dev分支,而是根据自己的需要(功能开发,bug修改等)在本地创建自己的分支,本地创建的分支不要push到远端

  4. 开发人员尽量按照下述步骤push代码

    1. 在自己创建的分支(test)上编辑完成功能开发或者bug修改

    2. add commit自己的修改git add -u,git commit -m "your conment"

    3. 准备进行push之前先根据实际情况对分支上的commit进行rebasegit rebase -i HEAD~n

    4. rebase完commit之后切换到dev分支git checkout dev

    5. 拉取最新的dev分支内容git pull

    6. 切换到test分支进行rebasegit checkout test,git rebase dev

    7. 如果rebase无冲突则进入步骤9,

    8. 解决冲突并告诉git冲突已解决git add -u,注意只需要add即可,不需要commit,这次的add相当于向冲突的commit中补充内容

    9. 再次切换到dev分支git checkout dev

    10. 进行合并,将test分支合并到devgit merge test

    11. 推送内容到远端git push如果此时又有人push新内容到dev分支,push时git会提示需要重新拉取最新内容,此时需要将dev分支reset到merge之前,进行pull,如果直接pull会有冲突

    12. push时提示需要pull的情况下,先reset dev分支到merge之前的版本

      1. git reflog找到merge之前的commit sha1值

      2. git reset --hard sha1

      3. git pull拉取最新内容

    13. 切换到test分支,并参照步骤12中reset方法将test分支reset到rebase之前的版本

    14. 重新回到步骤6

    15. push完成后可以选择删除test分支或者继续在test分支上进行开发

    16. 删除test分支git branch -d test

    17. 切换到test分支继续进行开发git checkout test

  5. 管理master分支

将dev分支整合到master分支上

centos 6/7源码安装git

下载:tarballs

tar -xzf version.tar.gz

cd version-dir

  1. yum install epel-release # enable the EPEL repository

  2. yum install dh-autoreconf curl-devel expat-devel gettext-devel openssl-devel perl-devel zlib-devel -y # 安装依赖

  3. yum groupinstall development -y # 安装依赖

  4. yum install asciidoc xmlto docbook2X -y #安装依赖

  5. yum install gengetopt -y #安装依赖

  6. ln -s /usr/bin/db2x_docbook2texi /usr/bin/docbook2x-texi #软链接

  7. make configure

  8. /configure --prefix=/usr

  9. make all doc info

  10. make install install-doc install-html install-info