Rewrite Git history via drag-and-drop
retcon.app
retcon.app
Create a new branch, called "preSplit", at the commit where you want to split. Take your actual branch and reset it to one commit prior. Grab the first set of changes you want from "preSplit" and commit. Repeat until each distinct set of changes has its own commit. If needed, rebase commits after "preSplit" onto your current branch.
I'll do it for you, for a modest fee!
https://github.com/jesseduffield/lazygit?tab=readme-ov-file#...
Oh you edited to say drag and drop. Lazygit is a TUI and patches are very much keyboard driven. Still worth thinking about? It’s free!
So far the implementation goes like this: you enter Edit mode on a commit; you unstage some lines; and you confirm. The lines are yanked from the commit, and added to a new commit that you just have to title. I just use it on the Retcon repo and it's real cool to have.
https://martinvonz.github.io/jj/latest/cli-reference/#jj-spl...
If you can make merge conflicts less dumb then I'm there!
Then many people should purchase SmartGit client. Which supports more of the same thing (with couple more clicks, granted) but also has a proper tree view. Also supports linux ffs.
Never working with git without it again.
It would take a lot for me to move because I already pay for Jetbrains IDE.
I already posted in this thread but I just love these two tools and wish more people knew about both of them.
[1] https://docs.syntevo.com/SmartGit/Latest/HowTos/Modifying-th...
I don't know why the docs are this way, it's literally that. Maybe old version or something. This page is closer to the truth.
https://docs.syntevo.com/SmartGit/Latest/Manual/GUI/Branch/R...
You can download it and check it out, they have trial licenses.
lazygit is really cool, and is a lot more full-featured than Retcon. But, the core "rewrite with zero friction" feature of Retcon is still unmatched, I think.
For instance: while lazygit does allow you to reorder commits without entering a separate mode, that's only if each move is conflict free. If you have two commits that need to both be moved at once, then in lazygit, you'll have to resort to a regular interactive rebase (so, with the separate planning and execution steps, no undo or preview along the way, etc).
In Retcon, if a commit move results in a conflict, that doesn't matter; you can keep making changes to your history anyway, and then resolve any remaining conflicts when you're ready. It makes the workflow super fluid.
There's probably still a ton Retcon could learn from lazygit/magit/jj, though!
I didn't realize Retcon could do this from the website, nice!
I wonder how similar your approach is to [jj's approach to conflicts]; whether you reinvented the same way of modelling conflicts in the repo or use a different one. (See also the link to the technical docs from that page)
https://gitbutler.com/ also [borrowed this idea] from jj.
[jj's approach to conflicts]: https://martinvonz.github.io/jj/latest/conflicts/
[borrowed this idea]: https://blog.gitbutler.com/fearless-rebasing/
So, there are several tools exploring these ideas, but there are interesting differences in (for example) how close to Git each of these approaches stays.
Retcon is pretty different: during a rebase, the state of everything is only stored in RAM, not serialized to the repo. So while you can postpone resolving conflicts until you're done putting commits in place, you do have to do so before you go do something else in your repo.
The RAM representation is basically a list of commits (well, commit-likes), what I call a virtual history. It's the history you want to get to, but that's not currently representable with a regular, physical Git history.
It is one of those rare birds that is both more powerful than the tool that it replaces while also being drastically easier to use. I am (was?) a git power user. It took me all of a day to replace git with jj and generously the rest of the week to become essentially as fluent. I will never go back.
Chris Krycho's post[2] was what originally sold me and I hope it sells you too.
Steve klabnik's tutorial is excellent as well. https://steveklabnik.github.io/jujutsu-tutorial/introduction...
Maybe I'll check it out. Deferring conflict resolution is definitely a killer feature.
It’s trivial to split a change in two. So your working copy is constantly snapshotted, and when you’re finished you `jj split` and choose the parts you want to keep. The rest is moved out into a new change.
That workflow is in practice basically identical to the `git add -p` one, though the terminology is a bit different and there are some greatly simplifying changes under the hood.
I'm fine with the history capturing what has actually happened. a Git history isn't something that is supposed to be admired as if it were a work of art.
The git history is the scaffolding, not the cathedral itself.
Even the source code isn't the cathedral, that's more super-structure. The product is the goal.
During development of a thing it should be desirable to be able to handle/test just whatever the current thing is and clean up afterwards if necessary, without having to completely drop ability to use git. But this can impact later bisects - having temporary printf("fuck sadjkoisajhdfo")s spamming outputs, project entirely not building on a configuration that wasn't cared about at the moment (or worse, build successfully, but function off enough that it's not obvious that the commit was not intended to be touched).
And then there's the general thing of having a feature that you had been working on, but want to move it to some other branch. Or you committed things out of order and the committed order doesn't actually build in the middle. Or you didn't commit some file/change and thus have a sequence of ten completely-non-sensical non-functional commits.
The inverse question deserves asking - why would you want to leave in your primary commit history things not meant to ever be looked at?
So instead of:
* Change 1
* Fix typo
* Change 2
* Another typo
* Change 3
* That didn't work
* Ops, I did it again
* Revert Change 3
* Change 3 (final)
You'll merge: * Change 1
* Change 2
* Change 3
Which is much better, particularly if you have hundreds of developers working on the same codebase.And it is very easy to do that using `git rebase -i`.
(I don't see the need for a GUI)
To see a "clean" history, I can always use log options like git's -first-parent. It works great and doesn't delete history.
I can also see value there if you're not squashing commits at the PR level. I prefer just squashing commits so main becomes:
- Feature 1
- Feature 2
- BugFix 1
- Feature 4
etc.The individual branches have the "dirty" history which can be useful, and main is kept neat by having feature of fix-level changes which are quality controlled through gated-commits.
If you had to work on long-running feature branches which were more of a free-for-all so /branches/feature effectively becomes your "main" then I could see much more of an argument for re-writing history of individual contributors before merging into that feature branch.
I'd still argue you should just set up proper quality control on the feature branch and squash commits going into that, but that's the kind of overhead that can frustrate some teams, so I can better understand now the desire for a half-way cleaning between squashing and the full dirty history.
That way lies madness.
Code that takes a minute to write takes ten minutes to understand. Code is first and foremost for humans to understand, before it is for machines to execute. Otherwise there would be no need for comments, or sane names for functions. Or commit messages. Please be considerate to your readers.
Why is everything turning into subscription based? I understand that it is more favorable for the creator but I can't imagine having to pay monthly for everything I use. Imagine one day when my economy gets strangled, do I loose everything I can't afford subscribe to anymore?
Retcon's actually already available on Homebrew—someone kindly added it, unprompted!
And with the way Git stores information, sometimes you don't have any option but to rewrite history. e.g. when something changes on a committer identity, you have to rewrite all of their commits since that information is denormalized.
FWIW, this sounds like the kind of thing that signed commits would solve. If the coder/user commits anything that isn't signed, they can't push it into the origin repo in the first place.
Of course it's not hard to imagine how a program could potentially do a lot more. And I would understand if compared to that you called the functionality GitKraken provides as having nothing at all.
Sometimes, just moving things around further is enough to resolve the conflicts, too, if they're simple enough!
[1]: https://git-fork.com
SmartGit has had drag and drop for a long time. I actually rarely use it but there is almost no Git problem I can’t fix in like 2 clicks.
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
merge main
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
fml
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
fix 2
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
fix 1
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
CI fix
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
PR comments
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
Linter
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
Fix test
commit f5b5bd8f9eaa443d4020cbe918x742e7ddd22000
Author : John Doe <John.Doe@mail.com>
Date: Mon May 22 14:21:03 2023 -0400.
Implement new SSO featureBesides that, I like seeing and preserving this kind of history. And when I don't want to, there are ways to filter the logs.
Seeing a "PR comments" commit just turns into noise. It also makes me gather 10 commits together to try to piece back together the unit of work that was built. I just see no value in preserving this type of noise.
For example, reality could've been that there was no team involved at all and all those changes came to the original person the moment he made the PR. And the "PR comments" could just as easily refer to his own comments he added during when checking those CI messages and noticing something else and commenting on that not to forget.
For fun, here's a git log pre-rebase of some backup tag I have (final commits: https://github.com/dzaima/CBQN/commits/eccbac37ab15bd68320d9...):
f6bc866f (tag: backup/pre-rebase-si-bitwiden) ..aarch64
0fd19c39 Singeli n→8 bitwiden
ed2a0655 more Singeli utils
556aa17b use q_fbit more
a28adcbb minor src/README.md cleanup
d6d40fc7 .warning comment
9dcf2f75 .don't need customizeShape for explicitly-created bitarr
958a04a1 update Singeli submodule
159ee16e ..
ea43cb2d .
b067d7a8 !!
c588a381 fix ⟨1‿2⟩⊸⊏˘ mat
0e251720 .
8f049ede fast inds⊸⊏˘bits for 4-bit & 2-bit input & output cells
def8c196 fast inds⊸⊏˘bits for 8-bit input & output cells
1638f8d4 .valgrind false-positive hiding
1023aaa5 --replxx-read-only
bee4169e .more valgrind improvement
c3643fc6 use custom valgrind pdep/pext everywhere
45796542 fix out-of-bounds load on empty replxx line
bc5894b9 make bitp_get & bitp_set load/store u8 instead of u64
3b4381b2 include last power of two in fast-path ⌽˘
Most of that didn't compile on aarch64 before that last commit, even changes that could affect aarch64 as I sprinkled in some other things while working on the "main" thing as they came up.When I just want the end result, I can filter the logs or look at the merge commit. But this is valuable too - especially since you yourself might look back at it and remember not just what you wrote, but how.
As fun as it might look, I'm fairly certain that the original commit contents are entirely useless to anyone who isn't me, and by this point they're pointless to me too. I'm fairly certain it's entirely pointless other than a trip down the memory lane (which, granted, can be quite fun, but is entirely not worth basing the primary git log around).
I find this works really nicely, I can periodically clean up my commit history and do a full review of my changes so far and make sure they're all coherent before continuing. And doing this regularly makes it much easier to keep the commits nicely self contained. It's like `final_version_final_ii_for_real_final.xlsx` on top of git
What i want is for something to have a plan-THEN-act approach to rebasing. Like GParted, or... `git rebase -i`.
Additionally, Sublime Merge seems to have significantly more features with fairly similar UI.
It's a regular video recording, and then I noted down the chapter timestamps in an array. (see heroVideoChapterStartTimesSeconds at the very top of https://retcon.app/main.js) As the video is playing, the player uses this to know what chapter to highlight, and how much to fill its progress bar. (that's updateVideoChapters())
For example, if you are working in two different files -- you can reorder the commits so they appear together, and then combine them if that makes sense.
What are you trying to do? Are you embarrassed that you arrived at an end goal via a suboptimal sequence of steps, and are trying to present it in a way that conceals that fact? Is the auditor at the door? What's the end goal here?
The solution was to identify our changes, split them into meaningful feature commits, keeping upstream and our code as separate as possible. After this change, updating the upstream by ~2 years took about 4 days. Most importantly, the history is kept clean by marking what commits go where, and doing cleanup every couple of months (no code diffs are allowed at that moment, only git history may be rewritten).
The new history can also be exported as patches, so that any client can (selectively) apply them on top of their own hostapd.
Both of these features aren't very useful when they point at a "wip" or similar commit message.
By all means push lots of little commits to your branch while you're figuring stuff out, but squash and rewrite history into logical commits (usually just one) before landing the change on main.