Git 合并而不更改工作目录

Git 合并而不更改工作目录,git,Git,我有以下情况: * ab82147 (HEAD, topic) changes * 8993636 changes * 82f4426 changes * 18be5a3 (master) first 我想将(非快进)topic合并到master中。这要求我: git签出主机 git合并--无ff主题 但是签出master,然后将主题合并到其中会导致git更改我的工作目录(尽管最终结果与签出master之前的结果相同),而我遇到的问题是由于项目的大小,构建它需要大约30分钟(使用Incre

我有以下情况:

* ab82147 (HEAD, topic) changes
* 8993636 changes
* 82f4426 changes
* 18be5a3 (master) first
我想将(非快进)
topic
合并到
master
中。这要求我:

  • git签出主机
  • git合并--无ff主题
但是签出master,然后将主题合并到其中会导致git更改我的工作目录(尽管最终结果与签出master之前的结果相同),而我遇到的问题是由于项目的大小,构建它需要大约30分钟(使用IncrediBuild)虽然一切都没有改变,简直无法忍受

因此,我希望得到以下信息:

*   9075cf4 (HEAD, master) Merge branch 'topic'
|\  
| * ab82147 (topic) changes
| * 8993636 changes
| * 82f4426 changes
|/  
* 18be5a3 first

没有真正接触工作目录(或者至少以某种方式欺骗git)。

有趣!我不认为有一种内置的方法可以做到这一点,但你应该能够使用管道来修复它:

#/bin/bash
分支=主
#或者以一个论点为例:
#如果[$@eq 1];
#branch=“$1”;
#fi
#确保分支存在
如果!git rev parse--verify--quiet--heads“$branch”>/dev/null;然后
echo“错误:分支$branch不存在”
出口1
fi
#确保这可能是一个快速前进
如果[“$(git merge base HEAD$branch)”==“$(git rev parse$branch)”;然后
#查找与头关联的分支名称
currentbranch=$(git符号参考头| sed's@.*/@@')
#作出承诺
newcommit=$(echo“Merge branch'$currentbranch'”| git提交树$(git log-n1--pretty=%T HEAD)-p$branch-p HEAD)
#移动分支以指向新提交
git update ref-m“merge$currentbranch:由模拟无ff进行的合并”“refs/heads/$branch”$newcommit
其他的
echo“错误:将$currentbranch合并到$branch不会是一个快进过程”
出口1
fi
有趣的是
newcommit=
line;它使用提交树直接创建合并提交。第一个参数是要使用的树;那是树的头,你想保留它的枝干。提交消息在stdin上提供,其余参数命名新提交应该具有的父级。提交的SHA1被打印到标准输出,因此假设提交成功,您将捕获它,然后合并该提交(这将是一个快进过程)。如果您有强迫倾向,您可以确保提交树成功—但这应该是非常有保证的

限制:

  • 这只适用于可能是快速推进的合并。显然,在这种情况下,您实际上必须签出并合并(可能是在克隆中,以保存构建系统)
  • reflog消息是不同的。我故意这么做,因为当您使用
    --no ff
    时,git实际上会强制自己使用默认(递归)策略,但在reflog中编写这一策略将是一个谎言
  • 如果你处于超然状态,事情会变得很糟糕。那就得特别对待了

是的,我在一个玩具回购上测试了这个,它似乎工作正常!(虽然我没有试图破坏它。)

我能想到的最简单的方法是将
git克隆到一个单独的工作副本,在那里进行合并,然后
git拉回来。拉将是一个快进的过程,应该只影响真正已经更改的文件

当然,对于这样一个大型项目,制作临时克隆并不理想,需要相当大的额外硬盘空间。只要您不需要磁盘空间,就可以通过保留合并副本将额外克隆的时间成本降至最低(从长远来看)


免责声明:我还没有验证这是否有效。不过我认为应该这样做(git没有版本文件时间戳)

或者,您可以通过保存和恢复文件时间戳来直接修复症状。这有点难看,但写起来很有趣

Python时间戳保存/恢复脚本

#/usr/bin/env python
从optpasse导入OptionParser
导入操作系统
导入子流程
作为腌菜进口cPickle
尝试:
检查输出=子流程。检查输出
除属性错误外:
#check_输出是在Python2.7中添加的,因此它并不总是可用的
def检查输出(*args,**kwargs):
kwargs['stdout']=子流程.PIPE
proc=子流程.Popen(*args,**kwargs)
输出=proc.stdout.read()
retcode=proc.wait()
如果重新编码!=0:
cmd=kwargs.get('args')
如果cmd为None:
cmd=args[0]
err=subprocess.CalledProcessError(retcode,cmd)
err.output=输出
提出错误
其他:
返回输出
定义git_cmd(*args):
返回检查输出(['git']+list(args),stderr=subprocess.STDOUT)
def walk_git_tree(修订版):
“”“为git ls树列出的所有Blob(文件)生成(sha1,路径)对。”“”
tree=git_cmd('ls-tree','-r','-z',rev).rstrip('\0'))
对于树中的条目。拆分('\0'):
打印条目
模式,类型,sha1,路径=entry.split()
如果类型==“blob”:
产量(沙一路)
其他:
打印“警告:树包含非blob”
def收集时间戳(版本):
时间戳={}
对于sha1,步行树中的路径(修订版):
s=os.lstat(路径)
时间戳[路径]=(sha1,s.st_mtime,s.st_atime)
打印sha1,s.st_时间,s.st_时间,路径
返回时间戳
def restore_时间戳(时间戳):
对于路径,时间戳中的v.items()
如果os.path.isfile(路径):
sha1,mtime,atime=v
new_sha1=git_cmd('hash-object','--',path).strip()
如果sha1==new_sha1:
打印“还原”,路径为
os.utime(路径,(atime,mtime))
其他:
打印路径“已更改(未还原)”
elif os.path.exists(路径):
打印“警告:文件不再是文件…”
def main():
oparse=OptionParser()
opparse.add_选项('--save',