5 ms·
As I understood the scenario: 1. We're rewriting some commits. Let's say a chain of commits A through G. We want to make some change to commits A and D. 2. As
by martinvonz 11mo ago
As I understood the scenario:
1. We're rewriting some commits. Let's say a chain of commits A through G. We want to make some change to commits A and D.
2. As we're editing commit D, we realized that we need to make some changes to B to match the updated A.
3. Also while editing D we realized that we want to take a look at the state in A to see how something worked there.
With jj, here's what I would do:
1. Run `jj new A`, make the changes, then `jj squash` to squash the changes in to A and propagate them through the chain.
2. Run `jj new D` to make changes. We now notice that we wanted some changes to go into B. We can make the changes in the working copy and run `jj squash --into B -i` to interactively select the changes to squash into B.
3. Run `jj new A` to create a new working-copy commit on top of A, look around in your IDE or whatever, then run `jj edit <old commit on top of D>`. Then run `jj squash` to squash the remaining changes in the working copy into D.
I think you know the steps to do with Git so I won't bother writing them down. I find them less intuitive anyway.
- 1718627440 11mo ago1. Edit changes, run `git commit --fixup=A`. 2. Edit changes for D. Also edit changes for B. Interactively `git add` changes for B. `git commit --fixup=B`. 3. Finish changes for D, then call git commit --fixup=D Before push I run `git rebase --autosquash`, optionally `git rebase --exec='make check'` to rerun all the tests on the changed commits. Where is that "much harder"?
- martinvonz 11mo agoAh, I see, so you avoid interactive rebase and instead make all changes in the working copy and use `git commit --fixup` and `git rebase --autosquash` . Makes sense, but doesn't it break down when there are conflicts between the changes you're making in the working copy and the target commit? How do you adjust the steps if there were conflicts between the changes we wanted to make to A and the changes already present in B?
- 1718627440 11mo ago> Ah, I see, so you avoid interactive rebase and instead make all changes in the working copy and use `git commit --fixup` and `git rebase -i . I wouldn't say I avoid this, I also run `git rebase -i` several times per day, and I also often use `git commit --fixup` during a rebase. > Makes sense, but doesn't it break down when there are conflicts between the changes you're making in the working copy and the target commit? Yes, but wouldn't this be the same in JJ, when you do your changes on top of A, and later squash them into D? If you don't want to have the changes, you can also checkout D and do the changes there. Then you have two options: - `git commit --fixup`, later do `git rebase` - `git commit --amend`, and `git rebase --onto` Most times I do the thing described earlier and just solve the conflicts, because that's just a single command. Also when its only a single case, I use `git stash`. (The workflow then is do random fix, git stash, then figure out where these should go, git rebase) > How do you adjust the steps if there were conflicts between the changes we wanted to make to A and the changes already present in B? I just resolve them? I think I don't understand this question.
- martinvonz 11mo ago> I just resolve them? I think I don't understand this question. In order to make changes to commit A when there are conflicting changes in B, I was thinking that you would have to use interactive rebase instead because you can no longer make those changes in the working copy and use `git commit --fixup`, right? And because there will now be conflicts in commit B, you will be in this "interrupted rebase" state where you have conflicts in the staging area and it's a bit tricky (IMO) to leave those and look around somewhere else and then come back and resolve the conflicts and continue the rebase later. > Yes, but wouldn't this be the same in JJ, when you do your changes on top of A, and later squash them into D? The difference is that we don't end up in an interrupted rebase. If we squashed some changes into A and that resulted in conflicts in B, then we would then create a new working-copy commit on top of the conflicted B (I call all of the related commits B even if they've been rewritten - I hope that's not too confusing). We then resolve the conflicts and squash the resolution into B and the resolution gets propagated to the descendants. We are free at any time to check out any other commit etc.; there's no interrupted rebase or unfinished conflicts we need to take care of first. I hope that clarifies.