On Fri, Apr 2, 2021 at 6:36 PM Jerry Zhang <jerry@xxxxxxxxxx> wrote: > > I'm creating a script/tool that will be able to cherry-pick > multiple commits from a single branch, rebase them onto a > base commit, and push those references to a remote. > > Ex. with a branch like "origin/master -> A -> B -> C" > The tool will create "master -> A", "master -> B", > "master -> C" and either make local branches or > push them to a remote. This can be useful since code > review tools like github use branches as the basis > for pull requests. Not sure I understand the "master -> A", "master -> B" syntax. What do you mean here? > A key feature here is that the above happens without > any changes to the user's working directory or cache. > This is important since those operations will add > time and generate build churn. We use these steps > for synthesizing a "cherry-pick" of B to master. > > 1. cp .git/index index.temp > 2. set GIT_INDEX_FILE=index.temp > 3. git reset master -- . (git read-tree also works here, but is a bit slower) > 4. git format-patch --full-index B~..B > 5. git apply --cached B.patch > 6. git write-tree > 7. git commit-tree {output of 6} -p master -m "message" > 8. either `git symbolic-ref` to make a branch or `git push` to remote Yeah, folks have resorted to various variants of this kind of thing in the past. It is a clever way to handle some basic cases, but it does often fall short. It's unfortunate that cherry-pick and rebase cannot yet just provide this functionality (more on that below). It may also interest you that rebase has two different backends, one built on am (which in turn is built on format-patch + apply), and one built on the merge machinery (which the am --3way also uses when it needs to). We deprecated the format-patch + apply backend in part because it sometimes results in misapplied patches; see the "Context" subsection of the "BEHAVIORAL DIFFERENCES" section of the git-rebase manpage. However, the am version would at least handle basic renames, which I believe might cause problems for a direct format-patch + apply invocation like yours (I'll also discuss this more below). > I'm looking to improve the git apply step in #5. > Currently we can't use --cached in combination with > --3way, which limits some of the usefulness of this method. > There are many diffs that will block applying a patch > that a 3 way merge can resolve without conflicts. Even > in the case where there are real conflicts, performing > a 3 way merge will allow us to show the user the lines > where the conflict occurred. > > With the above in mind, I've created a small patch that > implements the behavior I'd like. Rather than disallow > the cached and 3way flags to be combined, we allow them, > but write any conflicts directly to the cached file. Since > we're unable to modify the working directory, it seems > reasonable in this case to not actually present the user > with any options to resolve conflicts. Instead, a script > or tool using this command can diff the temporary cache > to get the source of the conflict. Looks like you're focusing on content conflicts. What about path conflicts? For example, apply's --3way just uses a per-file ll_merge() call, meaning it won't handle renames, so your method would also often get spurious modify/delete conflicts when renames occur. How does your plan to just "cache" conflicts work with these modify/delete files? Will users just look for conflict markers and ignore the fact that both modified newfile and modified oldfile are present? I'm also curious how e.g. directory/file conflicts would be handled by your scheme; these seem somewhat problematic to me from your description. > Happy to address any feedback. After I address any major > changes I will add new tests for this path. Don't know the timeframe you're looking at, but I'm looking to modify cherry-pick and rebase to be able to operate on branches that are not checked out, or in bare repositories. The blocker to that traditionally has been that the merge machinery required a working directory. The good news is that I wrote a new merge backend that doesn't require a working directory. The bad news is I'm still trying to get that new merge backend through the review process, and no current release of git has a complete version of that new backend yet. Further, the changes to cherry-pick and rebase have not yet been started. There were some decisions to make too, such as how to handle the case with conflicts -- just report them and tell the user to retry with a checkout? Provide some kind of basic information about the conflicts? What'd be useful to you?