{"thread":{"id":"48163","subject":"A bug in git merge","startedAt":"2018-03-27T09:53:58Z","lastAt":"2018-03-27T12:49:50Z","messageCount":2,"participants":["Orgad Shaneh","Jeff King"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"343116","messageId":"CAGHpTBJ-4a5+5=303_N-n3TtUg_sXt6J1cad0WCQ4Kc-=HDdSA@mail.gmail.com","threadId":"48163","inReplyTo":null,"subject":"A bug in git merge","fromName":"Orgad Shaneh","fromEmail":"orgads@gmail.com","sentAt":"2018-03-27T09:53:52Z","receivedAt":"2018-03-27T09:53:58Z","isPatch":false,"sender":{"key":"orgads@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1246544?v=4"},"body":"Hi,\n\nIf I cherry-pick a commit that added a line, then merge another commit\nwhich removes this line, the line remains in the file instead of being\nremoved.\n\nThe following script demonstrates the bug.\n\nfile should be equivalent on both branches\n\ngit init\nseq 1 20 > file\ngit add file\ngit commit -m 'Initial'\nsed -i \"s/^5/5\\n55/\" file\ngit commit -a -m 'Added 55'\ngit checkout -b other HEAD^\ngit cherry-pick master\ngit commit --amend --author 'Author <a@b.c>' --no-edit # generate a new hash\nsed -i '/55/d' file\ngit commit -a -m 'Removed 55'\ngit checkout master\ngit merge --no-edit other\ngit diff other # Should be equal\n\n- Orgad\n"},{"id":"343121","messageId":"20180327124942.GA18448@sigill.intra.peff.net","threadId":"48163","inReplyTo":"CAGHpTBJ-4a5+5=303_N-n3TtUg_sXt6J1cad0WCQ4Kc-=HDdSA@mail.gmail.com","subject":"Re: A bug in git merge","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-03-27T12:49:43Z","receivedAt":"2018-03-27T12:49:50Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Mar 27, 2018 at 12:53:52PM +0300, Orgad Shaneh wrote:\n\n> If I cherry-pick a commit that added a line, then merge another commit\n> which removes this line, the line remains in the file instead of being\n> removed.\n> \n> The following script demonstrates the bug.\n> \n> file should be equivalent on both branches\n> \n> git init\n> seq 1 20 > file\n> git add file\n> git commit -m 'Initial'\n> sed -i \"s/^5/5\\n55/\" file\n> git commit -a -m 'Added 55'\n> git checkout -b other HEAD^\n> git cherry-pick master\n> git commit --amend --author 'Author <a@b.c>' --no-edit # generate a new hash\n> sed -i '/55/d' file\n> git commit -a -m 'Removed 55'\n> git checkout master\n> git merge --no-edit other\n> git diff other # Should be equal\n\nThis isn't a bug; it's the expected behavior for a 3-way merge.\n\nThe merge looks only at the two final states to be merged, and the merge\nbase. The three states we have are:\n\n    base: without line 55\n    ours: with line 55\n  theirs: without line 55\n\nAnd since only one side made a change, the resolution is to take the\nchange in the final result. The fact that the other branch actually\nmanipulated the file (and how it manipulated it) isn't considered at\nall.\n\nThe fact that it was a cherry-pick doesn't change that. A cherry-pick is\nan application of the same changes, but it has no history-relationship\nwith the original commit in Git.\n\nOne could argue for or against the user experience of history as a DAG,\n3-way endpoint merges, and how cherry-picks are stored, but this is all\nworking according to Git's design and not a bug.\n\n-Peff\n"}]}