2013-06-24 113 views
32

我有一个历史,看起来像这样:Git的平分与合并提交

* 3830e61 Add data escaping.    (Bad) 
* 0f5e148 Improve function for getting page template. 
* aaf8dc5 Merge branch 'navigation' 
|\ 
| * 3e667f8 Add icons. 
| * 43a07b1 Add menu styles.    (Breaks) 
| * 107ca95 Add Responsive Nav.   (Good) 
* | ea3d736 Add ‘Admin’ notice. 
* | 17ca0bb Update placeholder text. 
|/ 
* f52cc34 Add featured image. 
* 2abd954 Style placeholders. 

我想了解更多信息和git bisect,但我有这个历史的麻烦。我知道107ca95是好的,3830e61是坏的。当我运行git bisect时,提交107ca95..3e667f8被忽略。我碰巧知道43a07b1是引入回归的提交,但它从未被评估过。

这里大概我做了什么:

git checkout master 
git bisect start 
git bisect bad 
git bisect good 107ca95 
git bisect bad (multiple times) 

不管我做什么,107ca95..3e667f8从不签出进行测试。

有什么办法,我基本上可以平分线在“扁平化”的历史,以测试这些提交?我知道我可以使用交互rebase来平坦化历史,但我不想这样做。

+0

,发现标有所有“合并”分支的东西好,所以只留下合并提交自己的脚本。 –

+0

@BalogPal - 我看到了类似的建议,但似乎这样会将分支中的所有内容都标记为好,但实际上它包含错误的提交。对我来说奇怪的是,我甚至无法解决合并提交问题。奇怪的是,它解决了一个甚至不在提交范围内的提交。 – tollmanz

+0

没关系,如果第一个识别出合并,那么你做一个2-pass对分,然后你将它与它提交的提交合并。但是,如果你有更好的主意,只需将它应用于技术,关键是你可以使用脚本预先标记某些提交 –

回答

-4

你可以用“混帐start”命令中选择提交的范围。该命令的简介是:

git bisect start <bad> <good> 

在特定情况下,我认为正确的命令是:

git bisect start 3830e61 107ca95 
+2

这不等于OP的方法吗? – Basilevs

10

这是already answered

基本思路 - 寻找从特征 - 提交分支打破你的主人,你将不得不在ea3d736 - 相关的主人头顶上重新应用它。

以下是其中做的测试脚本的例子(从git doc)为你:

$ cat ~/test.sh 
#!/bin/sh 

# tweak the working tree by merging the hot-fix branch 
# and then attempt a build 
if git merge --no-commit ea3d736 && 
    make 
then 
    # run project specific test and report its status 
    ~/check_test_case.sh 
    status=$? 
else 
    # tell the caller this is untestable 
    status=125 
fi 

# undo the tweak to allow clean flipping to the next commit 
git reset --hard 

# return control 
exit $status 

运行:

git bisect start 3830e61 f52cc34 
git bisect good ea3d736 17ca0bb #If you want to test feature branch only 
git bisect run ~/test.sh 
7

这是一个非常旧的但没有答案的问题。我决定调查,发现我可以证明Git的行为与问题所说的不同。 一种解释是,Git的改进算法的对开,或提问做出标记提交一个错误。

我想了解更多和git bisect,但我有这个历史的麻烦。我知道107ca95是好的,3830e61是坏的。当我运行git bisect时,提交107ca95..3e667f8被忽略。我碰巧知道43a07b1是犯介绍了一个回归,但它永远不会评估

我写了一些代码来检查其是否评估或没有。我的测试显示它已被评估。运行下面的代码并验证提交消息Add menu styles.出现。

进一步意见:

  • “承诺107ca95..3e667f8被忽略”:请注意,提交你标记为“好”将不被评估,因为混帐已经知道它是好的。
  • 请参阅this article by Christian Couder中的“二分算法”一节。另外“检查合并基础”部分可能是相关的。
  • 如上所述,问题当然是使用不同的版本,然后我使用(问题是从2013年,Git 2.11是从2016年)。

平分运行输出

  • 注意,第一“添加管理员通知”被检查(第4行),因为其提供最多信息。 (请阅读上述文章中的“检查合并基础”。)
  • 从此,它会按预期平分线性历史。

# bad: [d7761d6f146eaca1d886f793ced4315539326866] Add data escaping. (Bad) 
# good: [f555d9063a25a20a6ec7c3b0c0504ffe0a997e98] Add Responsive Nav. (Good) 
git bisect start 'd7761d6f146eaca1d886f793ced4315539326866' 'f555d9063a25a20a6ec7c3b0c0504ffe0a997e98' 
# good: [1b3b7f4952732fec0c68a37d5f313d6f4219e4ae] Add ‘Admin’ notice. (Good) 
git bisect good 1b3b7f4952732fec0c68a37d5f313d6f4219e4ae 
# bad: [f9a65fe9e6cde4358e5b8ef7569332abfb07675e] Add icons. (Bad) 
git bisect bad f9a65fe9e6cde4358e5b8ef7569332abfb07675e 
# bad: [165b8a6e5137c40ce8b90911e59d7ec8eec30f46] Add menu styles. (Bad) 
git bisect bad 165b8a6e5137c40ce8b90911e59d7ec8eec30f46 
# first bad commit: [165b8a6e5137c40ce8b90911e59d7ec8eec30f46] Add menu styles. (Bad) 

代码

运行在的Python 3,使用Git 2.11.0。 命令来运行:python3 script.py

""" The following code creates a git repository in '/tmp/git-repo' and populates 
it with the following commit graph. Each commit has a test.sh which can be used 
as input to a git-bisect-run. 

The code then tries to find the breaking change automatically. 
And prints out the git bisect log. 

Written in response to http://stackoverflow.com/questions/17267816/git-bisect-with-merged-commits 
to test the claim that '107ca95..3e667f8 are never checked out'. 

Needs Python 3! 
""" 


from itertools import chain 
import os.path 
import os 
import sh 

repo = { 
0x3830e61: {'message': "Add data escaping.", 'parents': [ 0x0f5e148 ], 'test': False} , # Last: (Bad) 
0x0f5e148: {'message': "Improve function for getting page template.", 'parents': [ 0xaaf8dc5], 'test': False}, 
0xaaf8dc5: {'message': "Merge branch 'navigation'", 'parents': [ 0x3e667f8, 0xea3d736], 'test': False}, 
    0x3e667f8: {'message': "Add icons.", 'parents': [ 0x43a07b1], 'test': False}, 
    0x43a07b1: {'message': "Add menu styles.", 'parents': [ 0x107ca95], 'test': False} , # First:  (Breaks) 
    0x107ca95: {'message': "Add Responsive Nav.", 'parents': [ 0xf52cc34], 'test': True}, # First:  (Good) 
    0xea3d736: {'message': "Add ‘Admin’ notice.", 'parents': [ 0x17ca0bb], 'test': True}, 
    0x17ca0bb: {'message': "Update placeholder text.", 'parents': [ 0xf52cc34], 'test': True}, 
0xf52cc34: {'message': "Add featured image.", 'parents': [ 0x2abd954], 'test': True}, 
0x2abd954: {'message': "Style placeholders.", 'parents': [], 'test': True}, 
} 

bad = 0x3830e61 
good = 0x107ca95 


def generate_queue(_dag, parents): 
    for prev in parents: 
     yield prev 
     yield from generate_queue(_dag, _dag[prev]['parents']) 

def make_queue(_dag, inits): 
    """ Converts repo (a DAG) into a queue """ 
    q = list(generate_queue(_dag, inits)) 
    q.reverse() 
    seen = set() 
    r = [x for x in q if not (x in seen or seen.add(x))] 
    return r 

if __name__ == '__main__': 
    pwd = '/tmp/git-repo' 
    sh.rm('-r', pwd) 
    sh.mkdir('-p', pwd) 
    g = sh.git.bake(_cwd=pwd) 
    g.init() 

    parents = set(chain.from_iterable((repo[c]['parents'] for c in repo))) 

    commits = set(repo) 
    inits = list(commits - parents) 
    queue = make_queue(repo, inits) 

    assert len(queue) == len(repo), "queue {} vs repo {}".format(len(queue), len(repo)) 

    commit_ids = {} 
    # Create commits 
    for c in queue: 
     # Set up repo 
     parents = repo[c]['parents'] 
     if len(parents) > 0: 
      g.checkout(commit_ids[parents[0]]) 
     if len(parents) > 1: 
      if len(parents) > 2: raise NotImplementedError('Octopus merges not support yet.') 
      g.merge('--no-commit', '-s', 'ours', commit_ids[parents[1]]) # just force to use 'ours' strategy. 

     # Make changes 
     with open(os.path.join(pwd, 'test.sh'), 'w') as f: 
      f.write('exit {:d}\n'.format(0 if repo[c]['test'] else 1)) 
     os.chmod(os.path.join(pwd, 'test.sh'), 0o0755) 
     with open(os.path.join(pwd, 'message'), 'w') as f: 
      f.write(repo[c]['message']) 
     g.add('test.sh', 'message') 
     g.commit('-m', '{msg} ({test})'.format(msg=repo[c]['message'], test='Good' if repo[c]['test'] else 'Bad')) 
     commit_ids[c] = g('rev-parse', 'HEAD').strip() 

    # Run git-bisect 
    g.bisect('start', commit_ids[bad], commit_ids[good]) 
    g.bisect('run', './test.sh') 
    print(g.bisect('log')) 
过去我google搜索了类似的问题
+0

有趣的调查。 +1。不要忘记OP在2013年写了这个问题。自从最近的(2016年第四季度)git 2.11以后,'git bisect'可能会发生变化。 – VonC

+0

@VonC,谢谢!我已经写了,但现在强调它。 – Unapiedra