2013-06-24 52 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