我可以在不修改工作副本的情况下重新绑定Git分支吗? [英] Can I rebase a Git branch without modifying my working copy?

查看:104
本文介绍了我可以在不修改工作副本的情况下重新绑定Git分支吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我已经检出了我的主分支。我已经对主人进行了一些生产更改,现在我想将我的实验分支重新分配给最新的主人。但是,我想在不修改我的工作副本中的任何文件的情况下执行此操作。实质上,我希望所有的魔法都发生在.git目录中,而不需要触摸工作副本。



如果不是不要修改我的工作副本要求,这只是一个问题:

 #当前分支是master 
git checkout experimental
git rebase master
git checkout master

我真正的问题在于这会修改我工作中的时间戳复制,即使我通过检查我开始使用的完全相同的内容来结束。只要我运行git checkout experimental,任何包含实验分支变化的文件都会将它们的mtime设置为当前时间 - 并且自从上次重新设置实验以来,在master中更改的任何文件也一样。因为这些时间已经改变了,所以像构建工具这样的东西可以让他们知道他们需要再做一些工作,即使在我完成的时候,这些文件的内容并没有真正改变。 (就我而言,如果项目文件的时间戳发生变化,Visual Studio认为它需要花费大量的时间来卸载和重新加载项目。)我想避免这种情况。



有没有一种方法可以在一个步骤中完成上述所有操作,而不需要修改工作副本中的任何内容 (假设在重新绑定期间没有冲突)



(如果 冲突,我的首选是显示错误并中止整个操作,没有修改任何时间戳,但这只是我的偏好,并不是一个硬性要求 - 我不知道什么都可能。)



当然,我可以写一个脚本来捕捉mtimes,运行git,然后重置mtimes;但似乎Git可能已经有办法像rebase一样做而不会打扰工作副本,因为rebase实际上是关于增量,而不是文件的实际内容。

有没有办法在一个步骤中完成上述所有操作,而不需要修改工作副本中的任何内容? $ b $

这是不可能的(不创建工作副本的可修改副本 - 另请参阅Petr的答案),因为git会在工作树上执行所有merge-y操作(真正的合并,樱桃挑选,rebase,补丁应用程序)。例如,在知识广泛的JakubNarębski的答案之一中提到了几次:


无需触摸工作目录(和索引),合并(或重新分配)就无法工作,因为可能存在需要使用工作目录解决的合并冲突(和/或索引)。

是的,这是一个设计决定,但这是一个很容易理解的 - 它会有点儿的一件杂事来构建试图在内存中合并所需的所有结构,那么只要它遇到冲突,就会将所有内容都转储到工作树中,而只需要在工作树中首先完成。 (我不是一个git开发人员;不要把它当成绝对完整的真相,可能还有其他原因。)



我的建议,而不是编写脚本做所有这些多次操作,只需克隆存储库,在克隆中执行rebase,然后将其推回到原始存储库中:

  git clone项目项目为rebase 
cd项目为rebase
git分支实验性来源/实验性
git rebase master实验性
git push来源实验性

当然假设您的原始资料库中没有签出实验。如果是,而不是推,你会做一些像 git fetch ../project-for-rebase实验; git reset --hard FETCH_HEAD 或更易读, git remote add for rebase ../project-for-rebase; git fetch for-rebase; git reset --hard for-rebase / experimental 。这自然会触及原始和重新发布的实验分支之间的任何文件,但这绝对是正确的行为。 (当然,这不是你给出的例子,但我希望这些说明是一般的!)


Suppose I have my "master" branch checked out. I've committed some production changes to "master", and now I want to rebase my "experimental" branch onto the latest master. But, I want to do this without modifying any files in my working copy. Essentially, I want all the magic to happen inside the .git directory, without touching the working copy.

If not for the "don't modify my working copy" requirement, this would just be a matter of doing:

# current branch is master
git checkout experimental
git rebase master
git checkout master

My real problem is that this modifies timestamps in my working copy, even though I'm ending by checking out the exact same content I started with. As soon as I run "git checkout experimental", any files that contain changes in the experimental branch will get their mtime set to the current time -- and so will any files that were changed in master since the last time I rebased experimental. Because the mtimes have changed, things like build tools get the idea that there's work they need to do again, even though, by the time I'm done, the files' contents haven't actually changed. (In my case, it's that if a project file's timestamp changes, Visual Studio thinks it needs to spend a lot of time unloading and reloading the project.) I want to avoid that.

Is there a way to do all of the above in one step, without ever modifying anything in the working copy (assuming there are no conflicts during the rebase)?

(If there are conflicts, my preference would be to show the error and then abort the entire operation, without ever modifying any timestamps. But that's just my preference, not a hard requirement -- I don't know what all is possible.)

Of course I can write a script to capture the mtimes, run git, and then reset the mtimes; but it seems likely that Git would already have a way to do things like rebase without bothering the working copy, since the rebase is really about the deltas, not the files' actual contents.

解决方案

Is there a way to do all of the above in one step, without ever modifying anything in the working copy?

This is unfortunately impossible (without creating a modifiable copy of the working copy - see also Petr's answer), because git performs all merge-y operations (real merges, cherry-picks, rebases, patch application) on the work tree. This is mentioned several times before, for example in one of the knowledgeable Jakub Narębski's answers:

There is no way that merge (or rebase) can work without touching the working directory (and index), as there can be merge conflicts that have to be resolved using working directory (and/or index).

Yes, it's a design decision, but it's a pretty understandable one - it'd be a bit of a chore to build up all the structure necessary to attempt a merge in memory, then as soon as it hits a conflict, dump everything into the work tree, when instead you could simply do it in the work tree in the first place. (I'm not a git developer; don't take this as absolute complete truth. There could be other reasons.)

My suggestion, rather than writing a script to do all that mtime manipulation, would be simply to clone the repository, perform the rebase in the clone, then push it back into your original repository:

git clone project project-for-rebase
cd project-for-rebase
git branch experimental origin/experimental
git rebase master experimental
git push origin experimental

That of course assumes that experimental isn't checked out in your original repo. If it is, instead of the push, you'd do something like git fetch ../project-for-rebase experimental; git reset --hard FETCH_HEAD or more readable, git remote add for-rebase ../project-for-rebase; git fetch for-rebase; git reset --hard for-rebase/experimental. That will naturally touch whatever files differ between the original and rebased experimental branches, but that's definitely correct behavior. (This wasn't the example you gave, of course, but I want these instructions to be general!)

这篇关于我可以在不修改工作副本的情况下重新绑定Git分支吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆