{"thread":{"id":"3083","subject":"Cancelling certain commits","startedAt":"2006-01-16T13:57:03Z","lastAt":"2006-01-17T10:03:52Z","messageCount":4,"participants":["Bahadir Balban","Andreas Ericsson","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"14730","messageId":"7ac1e90c0601160557r78599886nca9be9b6672a1bd7@mail.gmail.com","threadId":"3083","inReplyTo":null,"subject":"Cancelling certain commits","fromName":"Bahadir Balban","fromEmail":"bahadir.balban@gmail.com","sentAt":"2006-01-16T13:57:03Z","receivedAt":"2006-01-16T13:57:03Z","isPatch":false,"sender":{"key":"bahadir.balban@gmail.com","avatar":null},"body":"Hi,\n\nIf I'm not happy with the changes I made in certain commits during\ndevelopment, how do I cancel those commits and remove them from git\nrecords most cleanly?\n\nFor example if I did commits 1 to 10, and want to get rid of commit 3\nand 7, such that, the other commits are irrelevant to changes made in\n3 and 7, but may involve changes in the same file as 3 and 7 changed,\nhow do I handle it?\n\nFurthermore, how would I handle it if there was a commit 4, that\ndepended partially on commit 3? (For example if it uses a type that\nwas changed in commit 3?) Would I hand-edit commit 4 to fix it?\n\nMany thanks,\nBahadir\n"},{"id":"14731","messageId":"43CBAC0B.3020104@op5.se","threadId":"3083","inReplyTo":"7ac1e90c0601160557r78599886nca9be9b6672a1bd7@mail.gmail.com","subject":"Re: Cancelling certain commits","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-16T14:22:03Z","receivedAt":"2006-01-16T14:22:03Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Bahadir Balban wrote:\n> Hi,\n> \n> If I'm not happy with the changes I made in certain commits during\n> development, how do I cancel those commits and remove them from git\n> records most cleanly?\n> \n\nAs a general rule, it's desirable to do\n\n\t$ git revert --edit\n\nif you've made some programmatical error which is non-obvious (not a \ntypo, fe), as you can then make clear why that code wasn't proper for \nimplementation. It will also hinder others from doing the same mistake.\n\nEnough lessons though.\n\n> For example if I did commits 1 to 10, and want to get rid of commit 3\n> and 7, such that, the other commits are irrelevant to changes made in\n> 3 and 7, but may involve changes in the same file as 3 and 7 changed,\n> how do I handle it?\n> \n\n# make sure \"git status\" doesn't show any changes\n\n$ git branch anchor # to make a safe point to reset to if things go bad\n$ git reset --hard HEAD~7 # undo commits 3 - 10\n# replay commits 4, 5, 6, 8, 9\n$ for i in 6 5 4 2 1; do git cherry-pick -r anchor~$i || break; done\n# replay commit 10\n$ git cherry-pick -r anchor\n\n# done\n\nAnother variant:\n$ git format-patch --mbox -k HEAD~7\n$ git reset --hard HEAD~7\n# remove undesired commits from the files created\n$ git am -k 000*\n\n# done\n\nIf some commits depend on other commits both of these will fail and \nyou'll have to fix up by hand.\n\n\n> Furthermore, how would I handle it if there was a commit 4, that\n> depended partially on commit 3? (For example if it uses a type that\n> was changed in commit 3?) Would I hand-edit commit 4 to fix it?\n> \n\nSome more lecturing then;\nYou should have used a topic-branch to introduce such changes. This is \nalways desirable when making a change that requires a series of patches.\n\nIf this didn't actually require several commits you should have done \nthem as one (I always try to make sure my projects at least compile \ncleanly, even in topic-branches although they may contain warnings about \nstatic but unused functions and variables).\n\nAs for fixing up commits by hand when they're already written to the \nobject database, you can't really do that (in an easy way, at least). \nWhat you can do is use \"git format-patch\" to get patches in mbox format \nfor all the commits you eventually wish to keep, then do\n\n$ git reset --hard <one-committish-*after*-undesired>\n$ git cat-file commit HEAD > msg\n$ git reset --soft HEAD~1\n# edit changed files and msg\n$ git commit -F msg changed_file1.c changed_file2.c changed_filen.c\n\nNote that in all cases you should create an anchor branch to get you \nback to where you were in case something goes wrong, and never *ever* do\n\n$ git prune\n\non a repo where you're juggling loose commits like this (although that \nshould actually be safe when you create 'anchor' as a branch rather than \nas a tag, which Junio usually recommends).\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"},{"id":"14754","messageId":"7vvewjlowk.fsf@assigned-by-dhcp.cox.net","threadId":"3083","inReplyTo":"43CBAC0B.3020104@op5.se","subject":"Re: Cancelling certain commits","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-01-16T23:43:39Z","receivedAt":"2006-01-16T23:43:39Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Andreas Ericsson <ae@op5.se> writes:\n\n ... (all the good stuff not repeated).\n\nAs a general rule, first of all, make sure that this kind of\n\"cleaning up the history\" can be done only before you make your\nhistory available to others, and not after.\n\n> # make sure \"git status\" doesn't show any changes\n>\n> $ git branch anchor # to make a safe point to reset to if things go bad\n> $ git reset --hard HEAD~7 # undo commits 3 - 10\n> # replay commits 4, 5, 6, 8, 9\n> $ for i in 6 5 4 2 1; do git cherry-pick -r anchor~$i || break; done\n> # replay commit 10\n> $ git cherry-pick -r anchor\n\nI think \"6 5 4 2 1 0\" would be sweeter.  rev~0 == rev\n\n> ..., and never *ever*\n> do\n>\n> $ git prune\n>\n> on a repo where you're juggling loose commits like this (although that\n> should actually be safe when you create 'anchor' as a branch rather\n> than as a tag, which Junio usually recommends).\n\nSorry, I do not understand this part.  tags and branch heads are\nused in the same way to determine what objects to protect from\n\"prune\", so I thought there was no difference from the safety\npoint of view between the anchor being a branch or a tag.\n"},{"id":"14777","messageId":"43CCC108.5000404@op5.se","threadId":"3083","inReplyTo":"7vvewjlowk.fsf@assigned-by-dhcp.cox.net","subject":"Re: Cancelling certain commits","fromName":"Andreas Ericsson","fromEmail":"ae@op5.se","sentAt":"2006-01-17T10:03:52Z","receivedAt":"2006-01-17T10:03:52Z","isPatch":false,"sender":{"key":"ae@op5.se","avatar":"https://gravatar.com/avatar/426e89595c75a8f5252dd0c989e5fabe5bcac616e68557427ad9aef6b0ca342a?d=mp&s=160"},"body":"Junio C Hamano wrote:\n> Andreas Ericsson <ae@op5.se> writes:\n> \n>># make sure \"git status\" doesn't show any changes\n>>\n>>$ git branch anchor # to make a safe point to reset to if things go bad\n>>$ git reset --hard HEAD~7 # undo commits 3 - 10\n>># replay commits 4, 5, 6, 8, 9\n>>$ for i in 6 5 4 2 1; do git cherry-pick -r anchor~$i || break; done\n>># replay commit 10\n>>$ git cherry-pick -r anchor\n> \n> \n> I think \"6 5 4 2 1 0\" would be sweeter.  rev~0 == rev\n> \n\nDidn't know that. The day isn't a complete loss already. :)\n\n> \n>>..., and never *ever*\n>>do\n>>\n>>$ git prune\n>>\n>>on a repo where you're juggling loose commits like this (although that\n>>should actually be safe when you create 'anchor' as a branch rather\n>>than as a tag, which Junio usually recommends).\n> \n> \n> Sorry, I do not understand this part.  tags and branch heads are\n> used in the same way to determine what objects to protect from\n> \"prune\", so I thought there was no difference from the safety\n> point of view between the anchor being a branch or a tag.\n> \n\nYou're right. That's weird though, because I distinctly remember being \nbitten by this when I was very new to git. OTOH, I probably did \nsomething stupid that broke the repo before, and my girlfriend provided \nplenty distraction so I didn't do the pruning and the reset'ing on the \nsame day.\n\nWould a tag with the same name in a central repo overwrite a local one \nwhen \"git fetch --tags\" is used? I think I did this over http, but I'm \nnot sure. I know I had to clean up un-annotated tags that got pushed by \naccident after I had restored the lost commits though, so this could be \na cause (there was an 'anchor' tag in the shared repo as well).\n\n-- \nAndreas Ericsson                   andreas.ericsson@op5.se\nOP5 AB                             www.op5.se\nTel: +46 8-230225                  Fax: +46 8-230231\n"}]}