当前位置:  开发笔记 > 编程语言 > 正文

如何修复错误的合并,并将您的好提交重放到固定合并?

如何解决《如何修复错误的合并,并将您的好提交重放到固定合并?》经验,为你挑选了6个好方法。

我意外地将一个不需要的文件(filename.orig在解析合并时)提交到我的存储库几个提交之前,直到现在我才注意到它.我想从存储库历史记录中完全删除该文件.

是否可以重写更改历史记录,以便filename.orig从未首先添加到存储库中?



1> CB Bailey..:

如果您的情况不是问题中描述的情况,请不要使用此配方.此配方用于修复错误的合并,并将您的好提交重放到固定合并上.

虽然filter-branch会做你想要的,但这是一个非常复杂的命令,我可能会选择这样做git rebase.这可能是个人偏好.filter-branch可以在一个稍微复杂一点的命令中完成它,而rebase解决方案是一次一步地执行等效的逻辑操作.

尝试以下食谱:

# create and check out a temporary branch at the location of the bad merge
git checkout -b tmpfix 

# remove the incorrectly added file
git rm somefile.orig

# commit the amended merge
git commit --amend

# go back to the master branch
git checkout master

# replant the master branch onto the corrected merge
git rebase tmpfix

# delete the temporary branch
git branch -d tmpfix

(请注意,您实际上并不需要临时分支,您可以使用'分离的HEAD'来执行此操作,但是您需要记下git commit --amend步骤生成的提交ID 以提供给git rebase命令而不是使用临时分支名称.)


`git rebase -i`是非常有用的,特别是当你有多个rebase-y操作要执行时,但是当你没有真正指向某个人的肩膀并且可以看到他们正在做什么时,准确描述是一种正确的痛苦.编辑.我使用vim,但不是每个人都会满意:"ggjcesquash jddjp:wq"和"将顶行移到当前第二行之后并将第四行的第一个单词更改为'edit'现在保存和退出"似乎比实际步骤更复杂.你通常最终会得到一些`--amend`和`--continue`动作.
`git rebase -i`不会更快,仍然容易吗?$ git rebase -i 将正确的标记标记为"edit"$ git rm somefile.orig $ git commit --amend $ git rebase --continue但是由于某种原因,我仍然将文件放在最后的某个地方那时候我做到了.可能遗漏了一些东西.
@UncleCJ:你的文件是否在合并提交中添加了?这个很重要.此配方旨在处理错误的合并提交.如果在历史记录中正常提交中添加了不需要的文件,则无法正常工作.
我做了这个,但是在修改后的一个上面重新应用了一个新的提交,并使用相同的消息.显然,git在包含不需要的文件的旧的未修改提交和来自另一个分支的固定提交之间进行了3路合并,因此它在旧的提交之上创建了一个新的提交,以重新应用该文件.

2> 小智..:
简介:您有5种解决方案可供使用

原始海报说明:

我不小心将一个不需要的文件...提交到我的存储库几个提交之前...我想从存储库历史记录中完全删除该文件.

是否可以重写更改历史记录,以便filename.orig从未首先添加到存储库中?

有很多不同的方法可以完全从git中删除文件的历史记录:

    修改提交.

    硬重置(可能加上一个rebase).

    非交互式rebase.

    交互式rebase.

    过滤分支.

在原始海报的情况下,修改提交本身并不是一个选项,因为他之后做了几个额外的提交,但为了完整起见,我还将解释如何做,对于其他任何想要的人修改他们以前的提交.

请注意,所有这些解决方案都涉及以另一种方式更改/重写历史记录/提交,因此任何拥有旧提交副本的人都必须执行额外的工作以将其历史记录与新历史记录重新同步.


解决方案1:修改提交

如果您在先前的提交中意外地进行了更改(例如添加文件),并且您不希望该更改的历史记录再次存在,那么您可以简单地修改先前的提交以从中删除该文件:

git rm 
git commit --amend --no-edit

解决方案2:硬重置(可能加上Rebase)

与解决方案#1一样,如果您只想摆脱之前的提交,那么您还可以选择简单地对其父进行硬重置:

git reset --hard HEAD^

您的分支命令将难以恢复到以前的1 父提交.

但是,如果像原始海报一样,您在提交之后进行了几次提交以撤消更改,则仍然可以使用硬重置来修改它,但这样做也涉及使用rebase.以下是您可以用来在历史记录中进一步修改提交的步骤:

# Create a new branch at the commit you want to amend
git checkout -b temp 

# Amend the commit
git rm 
git commit --amend --no-edit

# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --preserve-merges --onto temp  master

# Verify your changes
git diff master@{1}

解决方案3:非交互式Rebase

如果您只想完全从历史记录中删除提交,这将有效:

# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp 

# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --preserve-merges --onto temp  master

# Or use `-p` insteda of the longer `--preserve-merges`
git rebase -p --onto temp  master

# Verify your changes
git diff master@{1}

解决方案4:交互式Rebases

此解决方案将允许您完成与解决方案#2和#3相同的操作,即修改或删除历史记录中的提交,而不是之前的提交,因此您选择使用哪种解决方案取决于您.出于性能原因,交互式rebase不太适合重新设置数百次提交,所以我会在这种情况下使用非交互式rebase或filter分支解决方案(见下文).

要开始交互式rebase,请使用以下命令:

git rebase --interactive ~

# Or `-i` instead of the longer `--interactive`
git rebase -i ~

这将导致git将提交历史记录回退到您要修改或删除的提交的父级.然后,它将以相反的顺序向您显示重新提交的列表,无论编辑器git设置为使用(默认情况下为Vim):

pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)

您要修改或删除的提交将位于此列表的顶部.要删除它,只需删除列表中的行.否则,将"选择"对1"编辑" 行,就像这样:

edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`

接下来,输入git rebase --continue.如果您选择完全删除提交,那么您需要做的就是(除了验证,请参阅此解决方案的最后一步).另一方面,如果您想修改提交,那么git将重新应用提交,然后暂停rebase.

Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

此时,您可以删除文件并修改提交,然后继续rebase:

git rm 
git commit --amend --no-edit
git rebase --continue

而已.作为最后一步,无论您是修改提交还是完全删除提交,最好通过将其与rebase之前的状态区分开来来验证没有对您的分支进行其他意外更改:

git diff master@{1}

解决方案5:过滤分支

最后,如果您想要从历史记录中彻底消除文件存在的所有痕迹,那么此解决方案是最佳选择,并且其他任何解决方案都不能完成任务.

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch '

这将从根提交开始从所有提交中删除.如果您只是想重写提交范围HEAD~5..HEAD,那么您可以将其作为附加参数传递给filter-branch,如本答案中所指出的 :

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch ' HEAD~5..HEAD

同样,在filter-branch完成之后,通过在过滤操作之前将分支与其先前状态区分开来来验证没有其他意外更改通常是个好主意:

git diff master@{1}

Filter-Branch替代方案:BFG Repo Cleaner

我听说BFG Repo Cleaner工具的运行速度比git filter-branch你快,所以你可能也想把它作为一个选项来检查.它甚至在过滤器分支文档中正式提到作为一种可行的替代方案:

git-filter-branch允许您对Git历史记录进行复杂的shell脚本重写,但如果您只是删除大文件或密码等不需要的数据,则可能不需要这种灵活性.对于那些操作,您可能需要考虑BFG Repo-Cleaner,一种基于JVM的git-filter-branch替代方案,对于这些用例,通常至少快10-50倍,并且具有完全不同的特性:

文件的任何特定版本都只清理一次.与git-filter-branch不同,BFG不会根据历史记录中提交的位置或时间以不同方式处理文件.这种约束给出了BFG的核心性能优势,并且非常适合清洗坏数据的任务-你不在乎哪里坏的数据,你只是希望它消失了.

默认情况下,BFG充分利用多核机器,并行清理提交文件树.GIT-滤波器分支清洁提交顺序(即,在单线程方式),虽然它 可以写入过滤器,包括它们自己的parallellism,在针对每一个执行的脚本提交.

该命令选项都远远超过git的过滤分支更严格,并致力于只是为了消除不必要的数据-例如任务:--strip-blobs-bigger-than 1M.

其他资源

    ProGit§6.4Git工具 - 重写历史.

    git-filter-branch(1)手册页.

    git-commit(1)手册页.

    git-reset(1)手册页.

    git-rebase(1)手册页.

    BFG Repo Cleaner(参见创作者自己的回答).



3> Schwern..:

如果你还没有提交任何东西,只git rm需要文件和git commit --amend.

如果你有

git filter-branch \
--index-filter 'git rm --cached --ignore-unmatch path/to/file/filename.orig' merge-point..HEAD

将通过每一个变化来自merge-pointHEAD,删除filename.orig和重写的变化.使用--ignore-unmatch意味着如果由于某种原因,更改中缺少filename.orig,命令将不会失败.这是git-filter-branch手册页中 Examples部分的推荐方法.

Windows用户注意事项:文件路径必须使用正斜杠


查看http://www.zyxware.com/articles/4027/how-to-delete-files-permanently-from-your-local-and-remote-git-repositories我发现它是最完整,最直接的解决方案涉及`过滤器分支'
谢谢!git filter-branch为我工作,其中作为答案给出的rebase示例没有:步骤似乎工作,但然后推送失败.拉了一下,然后推了成功,但文件还在.试图重做rebase步骤然后它合并冲突凌乱.我使用了一个稍微不同的filter-branch命令,这里给出了一个"改进的方法":http://github.com/guides/completely-remove-a-file-from-all-revisions git filter-branch -f --index-filter'git update-index --remove filename' .. HEAD
@atomicules,如果你试图将本地仓库推送到远程仓库,git将坚持首先从远程拉出,因为它有你本地没有的变化.您可以使用--force标志来推送到远程 - 它将完全从那里删除文件.但要小心,确保您不会强制覆盖除文件之外的其他内容.

4> 小智..:

这是最好的方法:http:
//github.com/guides/completely-remove-a-file-from-all-revisions

请务必先备份文件的副本.

编辑

不幸的是,Neon的编辑在审核过程中被拒绝了.
请参阅下面的Neons帖子,它可能包含有用的信息!


例如,删除*.gz意外提交到git存储库的所有文件:

$ du -sh .git ==> e.g. 100M
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch *.gz' HEAD
$ git push origin master --force
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git gc --aggressive --prune=now

那仍然不适合我?(我目前在git版本1.7.6.1)

$ du -sh .git ==> e.g. 100M

不知道为什么,因为我只有一个主分支.无论如何,我终于通过推入一个新的空的裸git存储库来真正清理我的git repo,例如

$ git init --bare /path/to/newcleanrepo.git
$ git push /path/to/newcleanrepo.git master
$ du -sh /path/to/newcleanrepo.git ==> e.g. 5M 

(是!)

然后我将它克隆到一个新目录,并将它的.git文件夹移到这个目录中.例如

$ mv .git ../large_dot_git
$ git clone /path/to/newcleanrepo.git ../tmpdir
$ mv ../tmpdir/.git .
$ du -sh .git ==> e.g. 5M 

(是的!终于清理干净了!)

在验证一切正常后,您可以删除../large_dot_git../tmpdir目录(可能在几周或几个月后,以防万一...)



5> Roberto Tyle..:

重写Git历史记录需要更改所有受影响的提交ID,因此每个正在处理该项目的人都需要删除他们旧的repo副本,并在清理完历史记录后进行新的克隆.不方便的人越多,你就越需要一个充分的理由去做 - 你多余的文件并没有真正造成问题,但如果只是在处理这个项目,那么如果你想要你也可以清理Git历史至!

为了使其尽可能简单,我建议使用BFG Repo-Cleaner,这是一种更简单,更快速的替代品,git-filter-branch专门用于从Git历史中删除文件.它让你的生活更轻松的一种方式是,它实际上默认处理所有引用(所有标签,分支等),但它也快10到50倍.

您应该仔细按照以下步骤操作:http://rtyley.github.com/bfg-repo-cleaner/#usage - 但核心位是这样的:下载BFG jar(需要Java 6或更高版本)并运行此命令:

$ java -jar bfg.jar --delete-files filename.orig my-repo.git

将扫描您的整个存储库历史记录,并且将删除任何名为filename.orig(不在您的最新提交中)的文件.这比使用git-filter-branch同样的东西要容易得多!

完全披露:我是BFG Repo-Cleaner的作者.


这是一个很好的工具:一个命令,它产生非常清晰的输出,并提供一个**日志文件,匹配每个旧的提交到新的**.我不喜欢安装Java,但这是值得的.

6> paulalexandr..:
You should probably clone your repository first.

Remove your file from all branches history:
git filter-branch --tree-filter 'rm -f filename.orig' -- --all

Remove your file just from the current branch:
git filter-branch --tree-filter 'rm -f filename.orig' -- --HEAD    

Lastly you should run to remove empty commits:
git filter-branch -f --prune-empty -- --all

推荐阅读
围脖上的博博_771
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有