* RFC: new git-splice subcommand for non-interactive branch splicing @ 2016-05-27 14:08 Adam Spiers 2016-05-27 15:27 ` Johannes Schindelin 2016-05-30 0:34 ` RFC: new git-transplant subcommand for non-interactively moving commits between branches Adam Spiers 0 siblings, 2 replies; 6+ messages in thread From: Adam Spiers @ 2016-05-27 14:08 UTC (permalink / raw) To: git mailing list Hi all, I finally got around to implementing a new git subcommand which I've wanted for quite a while. I've called it git-splice. Description ----------- git-splice(1) non-interactively splices the current branch by removing a range of commits from within it and/or cherry-picking a range of commits into it. It's essentially just a glorified wrapper around cherry-pick and rebase -i. Usage ----- Examples: # Remove commit A from the current branch git splice A^! # Remove commits A..B from the current branch git splice A..B # Remove commits A..B from the current branch, and cherry-pick # commits C..D at the same point git splice A..B C..D # Cherry-pick commits C..D, splicing them in just after commit A git splice A C..D # Remove first commit mentioning 'foo', and insert all commits # in the 'elsewhere' branch which mention 'bar' git splice --grep=foo -n1 HEAD -- --grep=bar HEAD..elsewhere # Abort a splice which failed during cherry-pick or rebase git splice --abort # Resume a splice after manually fixing conflicts caused by # cherry-pick or rebase git splice --continue N.B. Obviously this command rewrites history! As with git rebase, you should be aware of all the implications of history rewriting before using it. Code ---- Currently this is in alpha state: https://github.com/git/git/compare/master...aspiers:splice and I reserve the right to rewrite the history of that branch in the near future ;-) I realise that the code does not yet conform to the coding standards of the git project. For example, it relies on non-POSIX bash features, like arrays. I would be happy to fix this if there is a chance git-splice might be accepted for inclusion within the git distribution. (Presumably contrib/ is another possibility.) Also, I haven't yet written a proper man page for it. Motivation ---------- I wrote git-splice as the next step in the journey towards being able to implement a tool which automatically (or at least semi-automatically) splits a linear sequence of commits into a commit graph where ancestry exactly mirrors commit "dependency".[0] In other words, in this commit graph, a commit B would have commit A as an ancestor if and *only* if commit B cannot cleanly apply without A already being present in the branch. As a corollary, if commit F depends on D and E, but D and E are mutually independent, F would need to depend on a merge commit which contains D and E. Such a tool could be useful for a few reasons. Firstly, large patch series are much harder to review than single commits or small patch series, but typical development workflows often lead to large patch series. For example, if I work privately on a new feature for some hours / days / weeks, I will typically amass a bunch of commits which are not all directly related to the new feature: there are often refactorings, fixes for bugs discovered during development of the new feature, etc. I doubt I'm the only git user not disciplined enough to maintain neat branch organization for the whole of a long period of hacking! i.e. religiously maintaining one branch per bugfix, one branch per refactoring, and one branch for the new feature.[1] Typically, tidying up the branches comes a bit later, when I want to start feeding stuff upstream for review. Therefore being able to reduce the effort involved with breaking a large patch series into smaller related chunks seems potentially very useful. As well as making reviews smaller easier, this allows both the reviews and any corresponding CI to proceed in a more parallelized fashion. Some review systems can implicitly discourage reviews of large patch series, by treating each commit as a review in its own right and/or not providing sophisticated support for patch series. Gerrit is one example; gitlab and GitHub are counter-examples. I'm sure there are other use cases which I didn't think of yet. Next steps, and the future -------------------------- Obviously, I'd welcome thoughts on whether it would make sense to include this in the git distribution. In the longer term however, I'd like to write two more subcommands: - git-transplant(1) which wraps around git-splice(1) and enables easy non-interactive transplanting of a range of commits from one branch to another. This should be pretty straightforward to implement. - git-explode(1) which wraps around git-transplant(1) and git-deps(1), and automatically breaks a linear sequence of commits into multiple smaller sequences, forming a commit graph where ancestry mirrors commit dependency, as mentioned above. I expect this to be more difficult, and would probably write it in Python. Ideally, this tool would also be able to integrate with other workflow management tools[1] in order to effectively create / manage topic branches and track dependencies between them. Eventually, the utopia I'm dreaming about would become a reality and look something like this: git checkout -b new-feature while in_long_frenzied_period_of_hacking; do # don't worry too much about branch maintenance here, just hack git add ... git commit ... done # Break lots of commits from new-feature into new topic branches: git explode # List topic branches git work list # Manually complete tidy-up of those branches git push ... git send-email ... Feedback on any of this is very welcome! Thanks, Adam [0] https://github.com/aspiers/git-deps/#user-content-use-case-2-splitting-a-patch-series This type of dependency could be described as textual or syntactic or lexical, and is automatically detected by git-deps: https://github.com/aspiers/git-deps/ which I wrote a couple of years ago and previously announced on this list: http://thread.gmane.org/gmane.comp.version-control.git/262000/focus=262606 Of course, this is a somewhat naive approach in that it has no awareness of semantic dependencies, e.g. commit A changing file X in a way which only makes sense if commit B changing file Y is already present. However in my experience it's still a useful start in the right direction, saving a lot of time by detecting the "obvious" dependencies, and often revealing dependencies which I would have otherwise missed. [1] There are tools which can help with this, e.g. topgit, git-flow, and gitwork, which IMHO is particularly interesting. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFC: new git-splice subcommand for non-interactive branch splicing 2016-05-27 14:08 RFC: new git-splice subcommand for non-interactive branch splicing Adam Spiers @ 2016-05-27 15:27 ` Johannes Schindelin 2016-05-27 16:36 ` Adam Spiers 2016-05-30 0:34 ` RFC: new git-transplant subcommand for non-interactively moving commits between branches Adam Spiers 1 sibling, 1 reply; 6+ messages in thread From: Johannes Schindelin @ 2016-05-27 15:27 UTC (permalink / raw) To: Adam Spiers; +Cc: git mailing list Hi Adam, On Fri, 27 May 2016, Adam Spiers wrote: > Description > ----------- > > git-splice(1) non-interactively splices the current branch by removing > a range of commits from within it and/or cherry-picking a range of > commits into it. It's essentially just a glorified wrapper around > cherry-pick and rebase -i. It sounds as if you could accomplish the same with git checkout -b former-commits <split> git checkout -b latter-commits <base> git cherry-pick <split>..HEAD@{2} > Next steps, and the future > -------------------------- > > Obviously, I'd welcome thoughts on whether it would make sense to > include this in the git distribution. Far be I from discouraging you to work on these scripts, but I think that a really good place for such subcommands is a separate repository, as you have it already. There are already some rarely used subcommands in libexec/git-core/ cluttering up the space and I would be reluctant to add even more subcommands to the default Git installation delivered to every user. You can *always* just extend the PATH so that git-splice can be found; Then `git splice ...` will do exactly what you want. That is e.g. how git-flow works. (Of course I hope that you will maintain your scripts much, much better than git-flow, i.e. not abandon all users). > In the longer term however, I'd like to write two more subcommands: > > - git-transplant(1) which wraps around git-splice(1) and enables > easy non-interactive transplanting of a range of commits from > one branch to another. This should be pretty straightforward > to implement. This is just cherry-pick with a range... > - git-explode(1) which wraps around git-transplant(1) and > git-deps(1), and automatically breaks a linear sequence of commits > into multiple smaller sequences, forming a commit graph where > ancestry mirrors commit dependency, as mentioned above. I expect > this to be more difficult, and would probably write it in Python. You mean something like Darcs on top of Git. Essentially, you want to end up with an octopus merge of branches whose commits would conflict if exchanged. I implemented the logic for this in a shell script somewhere, so it is not *all* that hard (Python not required). But I ended up never quite using it because it turns out that in practice, the commit "dependency" (as defined by the commit diffs) does not really reflect the true dependency. For example, in my work to move large parts of rebase -i into a builtin, I have an entire series of commits that do nothing else but prepare the sequencer for rebase -i's functionality. Most of these commits touch completely separate parts of the code, so they would make independent branches in your git-explode command. Yet, that would destroy the story that the patch series tells, as the natural flow would get lost. Another major complication is that sometimes the "dependency as per the diff" is totally bogus. Take for example Git for Windows' patches on top of Git: there are a couple "sub branches" that add global variables to environment.c. By the logic of the overlapping (or touching) hunks, these sub branches should build on top of each other, right? But they are logically completely independent. So I think that this is a nice exercise, but in practice it will require a human to determine which commits really depend on each other. > Eventually, the utopia I'm dreaming about would become a reality and > look something like this: > > git checkout -b new-feature > > while in_long_frenzied_period_of_hacking; do > # don't worry too much about branch maintenance here, just hack > git add ... > git commit ... > done > > # Break lots of commits from new-feature into new topic branches: > git explode > > # List topic branches > git work list You would render me *really* impressed if you could come up with an automated way to determine logical dependencies between patches. Ciao, Johannes ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFC: new git-splice subcommand for non-interactive branch splicing 2016-05-27 15:27 ` Johannes Schindelin @ 2016-05-27 16:36 ` Adam Spiers 2016-05-28 7:06 ` Johannes Schindelin 0 siblings, 1 reply; 6+ messages in thread From: Adam Spiers @ 2016-05-27 16:36 UTC (permalink / raw) To: git mailing list Hi Johannes, Thanks for the quick reply! Responses inline below: On Fri, May 27, 2016 at 05:27:14PM +0200, Johannes Schindelin wrote: > On Fri, 27 May 2016, Adam Spiers wrote: > > > Description > > ----------- > > > > git-splice(1) non-interactively splices the current branch by removing > > a range of commits from within it and/or cherry-picking a range of > > commits into it. It's essentially just a glorified wrapper around > > cherry-pick and rebase -i. > > It sounds as if you could accomplish the same with > > git checkout -b former-commits <split> > git checkout -b latter-commits <base> > git cherry-pick <split>..HEAD@{2} Not really - that is missing several features which git-splice provides, e.g. - The ability to remove a non-consecutive list of commits from the branch. - The ability to insert commits at the same time as removing (granted, that's just in extra cherry-pick your method, but again that's another thing to orchestrate). - The ability to specify commits to remove / insert using arguments understood by git-rev-list. - The patch-id magic which is built into git-rebase. This would kick in if any of the commits to insert are already in <split>..HEAD@{2} (using your reference terminology). - A single command to orchestrate the whole workflow, including cleanup, and --abort and --continue when manual conflict resolution is required. This modularity should help a lot when building further tools which wrap around it in order to perform more complex tasks. This last point is perhaps the most important. Of course it's possible to do this manually already. But the whole point of git-splice is to automate it in a convenient and reliable manner. > > Next steps, and the future > > -------------------------- > > > > Obviously, I'd welcome thoughts on whether it would make sense to > > include this in the git distribution. > > Far be I from discouraging you to work on these scripts, but I think that > a really good place for such subcommands is a separate repository, as you > have it already. There are already some rarely used subcommands in > libexec/git-core/ cluttering up the space and I would be reluctant to add > even more subcommands to the default Git installation delivered to every > user. Sure, I appreciate the difficulty in deciding where to draw the line. My feeling is that rebase -i provides something tremendously important, which the vast majority of users use on a regular basis, but that git is currently missing a convenient way to *non-interactively* perform the same magic which rebase -i facilitates. And removing / reordering commits is surely one of the most common use cases of rebase -i, so I think a lot of people could benefit from some porcelain to automate that and allow building higher-level tools on top of it. I suspect the most popular use-case in the short term would be the infamous "oops, I only just noticed that I put that commit on the wrong branch, and now there's already a whole bunch of other commits on top of it". I would expect that reducing this solution to a single git-transplant(1) command would be pretty attractive for a lot of people. And of course GUIs / IDEs could incorporate it into their more beautiful front-ends. However, if it's not in git core, that's unlikely to happen. > You can *always* just extend the PATH so that git-splice can be found; > Then `git splice ...` will do exactly what you want. That is e.g. how > git-flow works. Sure, I've been using that trick since at least 2009 ;-) [0] > (Of course I hope that you will maintain your scripts > much, much better than git-flow, i.e. not abandon all users). I hope so too ;-) > > In the longer term however, I'd like to write two more subcommands: > > > > - git-transplant(1) which wraps around git-splice(1) and enables > > easy non-interactive transplanting of a range of commits from > > one branch to another. This should be pretty straightforward > > to implement. > > This is just cherry-pick with a range... No it's not: - git-transplant would be able to splice commits from one branch *into* (i.e. inside, *not* onto) another branch. - git-transplant would also take care of removing the commits from the source branch, but not before they were safely inside the destination branch. - git-transplant would orchestrate the whole workflow with a single command, complete with --abort and --continue. > > - git-explode(1) which wraps around git-transplant(1) and > > git-deps(1), and automatically breaks a linear sequence of commits > > into multiple smaller sequences, forming a commit graph where > > ancestry mirrors commit dependency, as mentioned above. I expect > > this to be more difficult, and would probably write it in Python. > > You mean something like Darcs on top of Git. Essentially, you want to end > up with an octopus merge of branches whose commits would conflict if > exchanged. Something like that, yes, but it's not as simple as a single octopus merge. It would support arbitrarily deep DAGs of topic branches. > I implemented the logic for this in a shell script somewhere, so it is not > *all* that hard (Python not required). But I ended up never quite using it > because it turns out that in practice, the commit "dependency" (as defined > by the commit diffs) does not really reflect the true dependency. > > For example, [snipped examples] Sure - I already covered this concern in footnote [0] of my previous mail; maybe you missed that? As I said there, in my experience, I have found it very useful to be able to automatically detect textual dependencies via git-deps, even though they do not represent the entire set of dependencies. I've even recorded a YouTube screencast demonstrating one such use case[1]. So please don't let the question for perfection become the enemy of the good ;-) > So I think that this is a nice exercise, but in practice it will require a > human to determine which commits really depend on each other. Of course - this is exactly why I wrote "or at least semi-automatically" in the first mail of this thread. But even though git-deps / git-explode can never automatically handle *all* dependencies, they can handle enough dependencies to be significantly useful. I have concrete real-world experience of that. In fact there is one scenario I am working on right now which is current proof of this (no coincidence, since that's what motivated me to take this next step on this journey and write git-splice): I have made a large bunch of small commits to a single text file (design document). Some are possibly contentious; some aren't. So I need to split them out into a series of smaller independent patch series which I can submit to gerrit for review, thereby making life easier for the reviewers and minimizing any bottlenecks where reviews for one change are blocked because another change hasn't been reviewed yet. And in this case, because the changes are all applying to a single file containing only natural language, git-deps correctly determines *all* dependencies, not just textual ones. > You would render me *really* impressed if you could come up with an > automated way to determine logical dependencies between patches. Hey, I would *really* impress myself if I could do that, too; after all, that would be a pretty sophisticated form of artificial intelligence :-) Thanks again for the feedback! Adam [0] https://github.com/aspiers/git-config/commit/287685408326 BTW there are currently 36 git-* scripts in that repo; you may or may not find it interesting to browse through them. [1] https://github.com/aspiers/git-deps#use-case-1-porting-between-branches In this case, git-deps can serve as an early warning system to flag when a backporting task's cost:reward ratio would be too high to justify starting work on it. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFC: new git-splice subcommand for non-interactive branch splicing 2016-05-27 16:36 ` Adam Spiers @ 2016-05-28 7:06 ` Johannes Schindelin 2016-05-28 11:24 ` Adam Spiers 0 siblings, 1 reply; 6+ messages in thread From: Johannes Schindelin @ 2016-05-28 7:06 UTC (permalink / raw) To: Adam Spiers; +Cc: git mailing list Hi Adam, please reply-to-all on this list. On Fri, 27 May 2016, Adam Spiers wrote: > My feeling is that rebase -i provides something tremendously > important, which the vast majority of users use on a regular basis, > but that git is currently missing a convenient way to > *non-interactively* perform the same magic which rebase -i > facilitates. Would it not make sense to enhance `rebase -i`, then? I, for one, plan to port my Git garden shears (at least partially) once I managed to get my rebase--helper work in. The shears script is kind of a "--preseve-merges done right": https://github.com/git-for-windows/build-extra/blob/master/shears.sh It allows you to (re-)create a branch structure like this: bud pick cafebabe XYZ pick 01234567 Another patch mark the-first-branch bud pick 98765432 This patch was unrelated mark the-second-branch bud merge the-first-branch merge the-second-branch Of course, this is interactive. But quite frankly, you want to be able to perform quite complicated stuff, and I think the command-line offers only an inadequate interface for this. > I suspect the most popular use-case in the short term would be the > infamous "oops, I only just noticed that I put that commit on the > wrong branch, and now there's already a whole bunch of other commits > on top of it". I have two workflows for that. The simpler one: git checkout other-branch git commit git checkout @{-1} Sometimes I need to call `git stash -p` before, and `git stash apply` after those calls. The more complicated one comes in handy when a complete rebuild takes a long time, and branch switching would trigger a rebuild: # Here, I stash what I *want* on the other branch git stash -p git worktree add throwaway other-branch cd throwaway git stash apply git commit I did use the approach you proposed a couple of times: just commit in the middle, and sort things out later. The problem: I frequently forgot, and if I did not, reordering the commits resulted in stupid and avoidable merge conflicts. > > > In the longer term however, I'd like to write two more subcommands: > > > > > > - git-transplant(1) which wraps around git-splice(1) and enables > > > easy non-interactive transplanting of a range of commits from > > > one branch to another. This should be pretty straightforward > > > to implement. > > > > This is just cherry-pick with a range... > > No it's not: > > - git-transplant would be able to splice commits from one branch > *into* (i.e. inside, *not* onto) another branch. Okay, but in case of merge conflicts, you still have to switch to the other branch, right? > - git-transplant would also take care of removing the commits from > the source branch, but not before they were safely inside the > destination branch. That assumes a workflow where you develop on one big messy branch and later sort it out into the appropriate, separate branches, right? I admit that I used to do that, too, but ever since worktrees arrived, I do not do that anymore: it resulted in too much clean-up work. Better to put the commits into the correct branch right away. Of course, that is just *my* preference. > - git-transplant would orchestrate the whole workflow with a single > command, complete with --abort and --continue. cherry-pick also sports --abort and --continue. > > > - git-explode(1) which wraps around git-transplant(1) and > > > git-deps(1), and automatically breaks a linear sequence of commits > > > into multiple smaller sequences, forming a commit graph where > > > ancestry mirrors commit dependency, as mentioned above. I expect > > > this to be more difficult, and would probably write it in Python. > > > > You mean something like Darcs on top of Git. Essentially, you want to end > > up with an octopus merge of branches whose commits would conflict if > > exchanged. > > Something like that, yes, but it's not as simple as a single octopus > merge. It would support arbitrarily deep DAGs of topic branches. Yes, of course. Because A - B - C - D might need to resolve into A - M1 - C - M3 X / B - M2 - D > > I implemented the logic for this in a shell script somewhere, so it is not > > *all* that hard (Python not required). But I ended up never quite using it > > because it turns out that in practice, the commit "dependency" (as defined > > by the commit diffs) does not really reflect the true dependency. > > > > For example, > > [snipped examples] > > Sure - I already covered this concern in footnote [0] of my previous > mail; maybe you missed that? I think it deserves more prominent a place than a footnote. > > So I think that this is a nice exercise, but in practice it will > > require a human to determine which commits really depend on each > > other. > > Of course - this is exactly why I wrote "or at least > semi-automatically" in the first mail of this thread. But even though > git-deps / git-explode can never automatically handle *all* > dependencies, they can handle enough dependencies to be significantly > useful. I have concrete real-world experience of that. I'd love to see those examples where it worked, because it sure did not work for me (I wasted two weeks to implement that script that I never used successfully). > I have made a large bunch of small commits to a single text file > (design document). Some are possibly contentious; some aren't. Ah. Well, as I said, I changed my workflow to use multiple worktrees with multiple branches. The contentious changes would go into at least one branch, more likely multiple. The uncontentious changes would go into another. And most likely at least some of those branches would cause merge conflicts. However, they would do so only once, not multiple times during the cleaning-up phase. I did actually track the time at some stage to determine what is faster. Sorting things into multiple branches won hands down (in my hands). And no: I did not believe it would. > So I need to split them out into a series of smaller independent patch > series which I can submit to gerrit for review, thereby making life > easier for the reviewers and minimizing any bottlenecks where reviews > for one change are blocked because another change hasn't been reviewed > yet. And in this case, because the changes are all applying to a single > file containing only natural language, git-deps correctly determines > *all* dependencies, not just textual ones. I do not buy that. When you introduce a section way down in the document for which you have to introduce a new definition in one of the first sections, logically those two changes belong to the same topic branch. Yet git-deps would have no chance to determine that. > > You would render me *really* impressed if you could come up with an > > automated way to determine logical dependencies between patches. > > Hey, I would *really* impress myself if I could do that, too; after > all, that would be a pretty sophisticated form of artificial > intelligence :-) Yep, I will definitely follow your progress! Ciao, Johannes ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: RFC: new git-splice subcommand for non-interactive branch splicing 2016-05-28 7:06 ` Johannes Schindelin @ 2016-05-28 11:24 ` Adam Spiers 0 siblings, 0 replies; 6+ messages in thread From: Adam Spiers @ 2016-05-28 11:24 UTC (permalink / raw) To: Johannes Schindelin; +Cc: git mailing list, Jon Seymour On Sat, May 28, 2016 at 09:06:59AM +0200, Johannes Schindelin wrote: > Hi Adam, > > please reply-to-all on this list. Sorry, I forgot that was the policy here. Every list and individual has different preferences on whether to Cc: on list mail, so I find it almost impossible to keep track of who prefers what :-/ > On Fri, 27 May 2016, Adam Spiers wrote: > > My feeling is that rebase -i provides something tremendously > > important, which the vast majority of users use on a regular basis, > > but that git is currently missing a convenient way to > > *non-interactively* perform the same magic which rebase -i > > facilitates. > > Would it not make sense to enhance `rebase -i`, then? You mean enhance it to support non-interactive usage? That wouldn't make much sense to me, given that -i is short for --interactive. Even if we added a new non-interactive rebase mode which let you edit the commits prior to rebasing them, I can't imagine how it would need to be any different to how non-interactive rebase -i currently works, i.e. setting GIT_SEQUENCE_EDITOR to a non-interactive command which modifies the rebase todo file passed via $1. Or maybe you are suggesting to enhance it to perform operations on the rebase todo list, such as removing a commit from the todo list, or moving a commit to a different position? But that sounds like scope creep to me; IMHO it would be cleaner for rebase -i to remain an unopinionated platform for history editing, rather than to make assumptions about common history editing workflows. I think those assumptions belong in higher-level porcelain tools. Or if you have some other enhancement in mind, please share details! > I, for one, plan to port my Git garden shears (at least partially) once I > managed to get my rebase--helper work in. The shears script is kind of a > "--preseve-merges done right": > > https://github.com/git-for-windows/build-extra/blob/master/shears.sh > > It allows you to (re-)create a branch structure like this: > > bud > pick cafebabe XYZ > pick 01234567 Another patch > mark the-first-branch > > bud > pick 98765432 This patch was unrelated > mark the-second-branch > > bud > merge the-first-branch > merge the-second-branch > > Of course, this is interactive. Interesting approach; thanks for sharing. At a first glance, this does sound similar to what topgit and gitwork are trying to achieve. I don't entirely understand it yet, however; it's hard to without knowing more about the structure of Git for Windows' integration branch and seeing a concrete example and/or comprehensive documentation. For example, it's not clear to me how generate_script() works, or how it lets you modify just one of the topic "sub-branches" and then automatically update all other sub-branches which depend on it? > But quite frankly, you want to be able to > perform quite complicated stuff Why do you say that? Splice and transplant operations are conceptually very straightforward, and not even particularly hard to implement. git-splice only took me a day or so, and I expect git-transplant to be quicker. The only complicated thing I want to implement is git-explode, but if I have splice and transplant "primitives" available, then it should be quite easy to implement git-explode as a series of splice/transplant operations. > and I think the command-line offers only an inadequate interface for > this. Please can you give an example where it would be inadequate? > > I suspect the most popular use-case in the short term would be the > > infamous "oops, I only just noticed that I put that commit on the > > wrong branch, and now there's already a whole bunch of other commits > > on top of it". > > I have two workflows for that. The simpler one: > > git checkout other-branch > git commit > git checkout @{-1} > > after those calls. > > The more complicated one comes in handy when a complete rebuild takes a > long time, and branch switching would trigger a rebuild: > > # Here, I stash what I *want* on the other branch > git stash -p > git worktree add throwaway other-branch > cd throwaway > git stash apply > git commit Neither of these workflows work with the scenario I described. In my scenario, the commit is already buried beneath other commits. > I did use the approach you proposed a couple of times: just commit in the > middle, and sort things out later. The problem: I frequently forgot, and > if I did not, reordering the commits resulted in stupid and avoidable > merge conflicts. I think you are misunderstanding me - I am not proposing this workflow; in fact that would be stupid because it's already in common usage. But I'm not even advocating it. I'm saying: - I do it regularly by accident (since when I am in the hacking zone, I am usually focused on the code, not on branch maintenance). - When I eventually realise I've done it, I need to go back afterwards and clean up the mess by decomposing the linear series of commits into separate topic branches. - No really good higher-level topic branch maintenance tools exist yet. - This is a common problem which many git users suffer from, based on a) my experience collaborating with others, b) personal feedback I've received on this topic, and c) googling for things like "git move commit to another branch". - There needs to be an easier way to clean up the mess, which minimises the pain resulting from merge conflicts. > > > > In the longer term however, I'd like to write two more subcommands: > > > > > > > > - git-transplant(1) which wraps around git-splice(1) and enables > > > > easy non-interactive transplanting of a range of commits from > > > > one branch to another. This should be pretty straightforward > > > > to implement. > > > > > > This is just cherry-pick with a range... > > > > No it's not: > > > > - git-transplant would be able to splice commits from one branch > > *into* (i.e. inside, *not* onto) another branch. > > Okay, but in case of merge conflicts, you still have to switch to the > other branch, right? Nope, if there are conflicts, you would either do git transplant --abort leaving you where you started, or fix the conflicts and then do git transplant --continue leaving you on the original branch, but with the transplanted commits no longer in that branch and instead in the target branch. > > - git-transplant would also take care of removing the commits from > > the source branch, but not before they were safely inside the > > destination branch. > > That assumes a workflow where you develop on one big messy branch and > later sort it out into the appropriate, separate branches, right? I admit > that I used to do that, too, but ever since worktrees arrived, I do not do > that anymore: it resulted in too much clean-up work. Better to put the > commits into the correct branch right away. Of course, that is just *my* > preference. It's *my* preference too, as I already stated above. That does not change the fact that even with the best intentions to avoid this workflow, it will still happen, *especially* when there are still no good higher-level tools which help avoid it. BTW gitwork is the closest I've seen to a tool which correctly addresses this: https://jonseymour.s3.amazonaws.com/git-work.html#_discussion but AFAIK it hasn't been updated in 3 years. Maybe Jon (cc'd) can comment on whether that means it already worked perfectly 3 years ago ;-) > > - git-transplant would orchestrate the whole workflow with a single > > command, complete with --abort and --continue. > > cherry-pick also sports --abort and --continue. If you look at my implementation of git-splice you'll see that it uses cherry-pick --abort and --continue. So thanks but I'm already fully aware of that :-) However that misses the point. Transplant needs to be a composite of multiple operations (splice into the target branch followed by splice to remove from the source branch). Therefore given that either of these splice operations can fail due to conflicts, the overall transplant needs to be orchestrated as a single workflow which supports --abort and --continue. For example, if the second splice fails with conflicts, the user needs to be able _with_a_single_command_ to roll back to the state before the transplant started. That means aborting the second splice, and reverting the first. If rollback is not as easy as a single command, the UX will create fear of failure, which will discourage users from using the tool. > > > > - git-explode(1) which wraps around git-transplant(1) and > > > > git-deps(1), and automatically breaks a linear sequence of commits > > > > into multiple smaller sequences, forming a commit graph where > > > > ancestry mirrors commit dependency, as mentioned above. I expect > > > > this to be more difficult, and would probably write it in Python. > > > > > > You mean something like Darcs on top of Git. Essentially, you want to end > > > up with an octopus merge of branches whose commits would conflict if > > > exchanged. > > > > Something like that, yes, but it's not as simple as a single octopus > > merge. It would support arbitrarily deep DAGs of topic branches. > > Yes, of course. Because > > A - B - C - D > > might need to resolve into > > A - M1 - C - M3 > X / > B - M2 - D Why are both M1 and M2 needed here? Can't D be a child of M1? A---M1---C---M3 / \ / B-' `-D-' > > > I implemented the logic for this in a shell script somewhere, so it is not > > > *all* that hard (Python not required). But I ended up never quite using it > > > because it turns out that in practice, the commit "dependency" (as defined > > > by the commit diffs) does not really reflect the true dependency. > > > > > > For example, > > > > [snipped examples] > > > > Sure - I already covered this concern in footnote [0] of my previous > > mail; maybe you missed that? > > I think it deserves more prominent a place than a footnote. I originally had it inline ;-/ but then moved it to a footnote since it was somewhat orthogonal to the main subject (git-splice) and I thought it was at risk of diluting focus. Sorry if that was the wrong decision. > > > So I think that this is a nice exercise, but in practice it will > > > require a human to determine which commits really depend on each > > > other. > > > > Of course - this is exactly why I wrote "or at least > > semi-automatically" in the first mail of this thread. But even though > > git-deps / git-explode can never automatically handle *all* > > dependencies, they can handle enough dependencies to be significantly > > useful. I have concrete real-world experience of that. > > I'd love to see those examples where it worked, because it sure did not > work for me (I wasted two weeks to implement that script that I never used > successfully). Yeah - I was hoping to make another YouTube video demonstrating one of them, but I've gone over my time budget simply by implementing git-splice (and unit tests) and then discussing it here :-/ > > I have made a large bunch of small commits to a single text file > > (design document). Some are possibly contentious; some aren't. > > Ah. Well, as I said, I changed my workflow to use multiple worktrees with > multiple branches. The contentious changes would go into at least one > branch, more likely multiple. The uncontentious changes would go into > another. Exactly, that's the ideal situation we're aiming for. The question is how to get there. Doing this branch maintenance manually is currently too inconvenient for most users. My belief is that building primitive operations such as splice and transplant will encourage the development of higher-level tools which can further automate the maintenance tasks. > And most likely at least some of those branches would cause merge > conflicts. Small nitpick: technically, branches can't cause merge conflicts; only operations such as cherry-pick / merge / rebase can cause them. > However, they would do so only once, not multiple times during > the cleaning-up phase. Sorry, I'm not sure I understand this, because I'm not sure exactly which operations you are referring to. > I did actually track the time at some stage to determine what is faster. > Sorting things into multiple branches won hands down (in my hands). And > no: I did not believe it would. It can certainly win, yes, and as I already said, this is my favoured approach too, when I remember to do it. But the win gets less likely for each dependency which exists between branches, in the absence of good branch management tools. > > So I need to split them out into a series of smaller independent patch > > series which I can submit to gerrit for review, thereby making life > > easier for the reviewers and minimizing any bottlenecks where reviews > > for one change are blocked because another change hasn't been reviewed > > yet. And in this case, because the changes are all applying to a single > > file containing only natural language, git-deps correctly determines > > *all* dependencies, not just textual ones. > > I do not buy that. When you introduce a section way down in the document > for which you have to introduce a new definition in one of the first > sections, logically those two changes belong to the same topic branch. Yet > git-deps would have no chance to determine that. Sure, but none of the 24 commits I am referring to do that - a fact of which I was entirely aware when I performed the analysis with git-deps. Sorry for omitting this from the above "because ..." clause. But I would like to reiterate: just because it is known not to work in all situations, it does *not* mean it can't be of use in any situation. Again, don't let the perfect become the enemy of the good. Cheers, Adam ^ permalink raw reply [flat|nested] 6+ messages in thread
* RFC: new git-transplant subcommand for non-interactively moving commits between branches 2016-05-27 14:08 RFC: new git-splice subcommand for non-interactive branch splicing Adam Spiers 2016-05-27 15:27 ` Johannes Schindelin @ 2016-05-30 0:34 ` Adam Spiers 1 sibling, 0 replies; 6+ messages in thread From: Adam Spiers @ 2016-05-30 0:34 UTC (permalink / raw) To: git mailing list On Fri, May 27, 2016 at 03:08:11PM +0100, Adam Spiers wrote: > Hi all, > > I finally got around to implementing a new git subcommand which I've > wanted for quite a while. I've called it git-splice. [snipped] > Next steps, and the future > -------------------------- > > Obviously, I'd welcome thoughts on whether it would make sense to > include this in the git distribution. > > In the longer term however, I'd like to write two more subcommands: > > - git-transplant(1) which wraps around git-splice(1) and enables > easy non-interactive transplanting of a range of commits from > one branch to another. This should be pretty straightforward > to implement. I've now written git-transplant too (and in the process of doing so, made many more enhancements to git-splice). Usage ----- Examples: # Move commits A..B from the current branch onto branch X git transplant A..B X # Move commits A..B from the current branch into branch X after commit C git transplant --after=C A..B X # Create a new branch X starting at ref Y, then # move commits A..B from the current branch onto X git transplant --new-from=Y C A..B X # Abort a transplant which failed during cherry-pick or rebase git transplant --abort # Resume a transplant after manually fixing conflicts caused by # cherry-pick or rebase git transplant --continue N.B. this command rewrites history, since after splicing the commits into the target branch, it removes them from the current branch. As with git rebase, you should be aware of all the implications of history rewriting before using it. Motivation ---------- See the rest of this mail thread. Code ---- > Currently this is in alpha state: > > https://github.com/git/git/compare/master...aspiers:splice > > and I reserve the right to rewrite the history of that branch in the > near future ;-) This still holds for git-splice, but also now for git-transplant too: the same branch now contains git-transplant and its test suite. Next steps ---------- - Wait for feedback. (Ideally I hope people will actually try both tools.) - If there is any appetite for eventually moving this into the distribution, it will still need quite a few things cleaning up first, e.g. making the coding style consistent with git's, getting rid of bashisms ... - (Eventually) write git-explode, as explained elsewhere in this thread. Cheers! Adam ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2016-05-30 0:34 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-05-27 14:08 RFC: new git-splice subcommand for non-interactive branch splicing Adam Spiers 2016-05-27 15:27 ` Johannes Schindelin 2016-05-27 16:36 ` Adam Spiers 2016-05-28 7:06 ` Johannes Schindelin 2016-05-28 11:24 ` Adam Spiers 2016-05-30 0:34 ` RFC: new git-transplant subcommand for non-interactively moving commits between branches Adam Spiers
Code repositories for project(s) associated with this public inbox https://80x24.org/mirrors/git.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).