#worktree centric git
Explore tagged Tumblr posts
mentalisttraceur-software · 4 years ago
Text
I'm thinking that `git-worktree-mode` eventually becomes just one subcommand of a more fully-featured command.
In particular, I'm seeing a lot of value now in replacing `git worktree add`, to solve some problems:
Git uses absolute paths for everything worktree-related internally. This normally doesn't matter but will blindside you with problems if you ever move the repo folder or any of the worktree folders. Recent `git` versions have `git worktree repair` to fix this, so that's not too bad, but it's still annoying.
`git worktree add foo` always creates a new `foo` branch if no local `foo` branch exists, even if a remote branch named `foo` exists. To get "normal" behavior for remote branches, like what `git checkout foo` does, you need to do `git worktree add foo foo`. If you forget that, it is annoying and non-obvious to fix.
3 notes · View notes
mentalisttraceur-software · 4 years ago
Text
As foretold (by me) in the prophesies a couple rambling posts, my efforts to achieve a great briefly exciting (for me) workflow with multiple Git work trees have "matured" (I spent a few says compulsively thinking about it every once in a while) into `git-cotree`.
`git-worktree-mode` became `git-cotree --init`. The new functionality is "just" ergonomically and robustly creating and deleting work trees co-trees, CLI argument parsing, and help text.
It is the same `git` history/repository (so you can still get your hands on the earlier work , I just renamed it in GitHub (so the old GitHub repo URL should redirect to the new one into the indefinite future).
2 notes · View notes
mentalisttraceur-software · 4 years ago
Text
So worktree-centric Git usage is not worth it for small repos with little if any concurrent contributions.
When I `git clone` one of my personal projects just to make a quick change, I'm definitely not itching to put my repo into worktree mode. When I am creating a new repo from scratch, worktree mode also kinda just gets in the way. Because in those cases, I never feel the want for more than one working directory.
It mostly becomes worth it once you have a larger, more complex code base, or a larger, busier team. Basically, the usefulness grows in proportion to how much and how often you find yourself switching between branches. I find that it especially helps making it painless to pull changes apart into multiple separate branches, which can tremendously help with code review, and can also separate contentious or unfinished pull requests from other changes that the team can benefit from immediately.
That's a big part of why I'm so happy with my current worktree-centric approach - it means that with a script like git-worktree-mode can provide a very smooth upgrade path! The user experience is that when you feel you need multiple worktrees, you just run the script, get a setup which is extremely ergonomic for multiple worktrees, and move on with your work, all with barely an interruption.
1 note · View note
mentalisttraceur-software · 4 years ago
Text
git-worktree-mode
I have put a script on my GitHub to automatically convert a Git repository into the very slick setup for a worktree-centric workflow that I seem to have discovered.
The script takes care of a lot of little edge cases that my previous explanations didn't bother covering, that's why it's got so much stuff going on.
Specifically, it's trying to make sure it fails fast with a clear Git error message if you use it wrong, and it tries to automatically migrate your current working directory and any uncommitted changes you had into a worktree.
1 note · View note
mentalisttraceur-software · 4 years ago
Text
Worktree-centric Git workflow variant, which at a first discovery feels strictly superior to the others I came up with, minus being more hacky:
Start in the root directory of an existing normal repository.
`git stash` if you want to save any uncommitted changes to tracked files before "converting" the repo.
`git rm -rfq .` to clean up the entire working directory of everything but the `.git` folder and any untracked files - you can skip this if you just freshly cloned the repo with `-‍-no-checkout`.
`git config -‍-local core.bare true`, which doesn't actually change much, but does have the wonderful side-effect of properly restricting things - for example `git status`, `git commit`, and so on will now say "fatal: this operation must be run in a work tree" if you run it at the top directory of the repo and not in a worktree subdirectory.
`git worktree add foo` instead of `git checkout foo`, which creates directory `foo` with branch `foo` checked out, as you'd normally expect.
Gonna play with this variant for a while now and see if I find any flaws with this one. But I think this might be the one.
2 notes · View notes
mentalisttraceur-software · 4 years ago
Text
The worktree-centric Git workflow I'm experimenting with is now as follows:
`git clone` with the `-‍-bare` flag and the `-‍-single-branch` flag, because we don't want to pull any other branch until after the remote references for fetching are set up normally.
Create a directory inside the bare repository. I'll call it `x` in this example description, but it could be anything you find reasonable and which doesn't conflict with something Git is actually using.
`git config -‍-local remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'` in order to set up the normal connection between remote branches and local branches, which a `-‍-bare` clone skips setting up.
`git fetch` to get all the remote branches as a normal clone would, now that we set the fetch refspec.
`git worktree add x/foo foo` instead of `git checkout foo` if `foo` exists on the remote, or `git worktree add x/foo` if `foo` doesn't exist on the remote. The second instance of the branch name is what causes `git worktree` to notice if there is an `origin/foo` reference and if so make the local branch "track" it as normal. Of course once it's checked out into a worktree, it remains checked out in that directory, even as you check out other branches to their directories.
The conventional origin fetch refspec thing is pretty nice unless you prefer manually dealing with linking local branches to the remote as needed just to make fetches and pulls work correctly. Similarly, it's really annoying to remember the extra repetition of the branch name in `worktree add`, but it's the least annoying way to make sure branches which already exist on the remote have their "upstream" set.
Obviously Git's built-in commands are creaking here, because Git assumes a different workflow. But this workflow could probably be tucked into a scripts or two, which you could maybe even put into your Git install's folder somewhere to get them to work as `git` subcommands.
2 notes · View notes
mentalisttraceur-software · 4 years ago
Text
Another problem with worktree-centric bare-clone git workflow:
`git pull` and `git fetch` without specifying the branch name start turning into a mess. They seem to keep wanting to use the bare repo's current branch, rather than the worktree's current branch.
Sometimes this is actually preferable - a lot of the time at work I want to pull the master branch and merge or rebase in my current local branch to get the latest changes.
But other times I want to actually pull the latest changes to my current branch, because some team member has made changes to the same branch that I'm currently working on. (Actually, for me personally this is currently rare, usually we're working in our own branches or on a couple occasions I'm making changes on someone else's branch, but the possibility is there.)
Again, this seems like a situation where abandoning the `-‍-bare` clone part of this workflow might just make these problems go away.
1 note · View note
mentalisttraceur-software · 4 years ago
Text
One immediate downside I ran into with my new worktree-centric git workflow is if you do it the `-‍-bare` checkout way, the distinction between local and remote seems to get peeled back a bit.
`git branch` starts listing all remote repositories. `git log origin/{{ branch name }}` just doesn't work. This is a bit of a shame because sometimes it's nice to ask "what's the difference between what I currently have committed locally, and what was last committed on the remote?"
I think these problems are avoided if you don't do the bare checkout, but instead clone as normal into `{{ your repo name }}/{{ name of your main branch }}`, which has other upsides like not having to worry about colliding with Git's own directories in a bare checkout, but then the directory containing all your repo directories oes not get recognized as part of the git repo, and thus you can't run Git commands inside of it. Probably not a major downside for most people?
1 note · View note
mentalisttraceur-software · 4 years ago
Text
I've started experimenting with a Git workflow:
`git clone` with the `-‍-bare` flag,
create a `branches` directory in the bare repository (collision risk! does or will `git` use a directory with this name for anything in bare repos?),
`git worktree add branches/foo` instead of `git checkout foo`.
This makes a few things nicer for me.
I can have multiple branches checked out at once, which means I can
pause and resume work on different branches,
pull work apart into different branches, or
`git pull` and then `git merge` or `git rebase` with upstream branches
with less Git command hassle - no more needing to stash or commit incomplete or experimental changes, no more checkouts back and forth.
I don't have to rely on Git integration in as many places. It's a little personal thing, but I like reducing the need for Git-aware intelligence in my tools. Each checked-out branch now lives on the file system, in a directory named with the branch name, which means that auto-complete and search are just filesystem searches.
We'll see how it goes. I've been wanting each branch to be its own directory for a while, but now that I can actually do it, maybe I discover some downsides inherent to the approach.
4 notes · View notes
mentalisttraceur-software · 4 years ago
Text
3. `git worktree remove` does not delete parent directories that become empty. This is the right behavior if worktrees could be located anywhere, but in this workflow worktrees exist only as subdirectories of the repository directory, which changes what the most appropriate behavior is.
This only comes up if you use slashes in your branch names.
Which, come to think of it, actually effects `git worktree add {{ branch }}` too, because `git worktree add` assumes that any slash in the worktree name is just part of you saying where you want the worktree to be rather than part of the branch name itself.
I personally would be a little opposed to slashes in branch names nowadays, precisely because I've seen it have consequences like this. But I've been on teams where that's standard. And I don't want to get into workflow habits which are so fragile vs debatable choices by others.
I'm thinking that `git-worktree-mode` eventually becomes just one subcommand of a more fully-featured command.
In particular, I'm seeing a lot of value now in replacing `git worktree add`, to solve some problems:
Git uses absolute paths for everything worktree-related internally. This normally doesn't matter but will blindside you with problems if you ever move the repo folder or any of the worktree folders. Recent `git` versions have `git worktree repair` to fix this, so that's not too bad, but it's still annoying.
`git worktree add foo` always creates a new `foo` branch if no local `foo` branch exists, even if a remote branch named `foo` exists. To get "normal" behavior for remote branches, like what `git checkout foo` does, you need to do `git worktree add foo foo`. If you forget that, it is annoying and non-obvious to fix.
3 notes · View notes
mentalisttraceur-software · 4 years ago
Text
Sadly I'm not seeing a way to totally fix #1.
Relative paths do robustly work in the worktree's `.git` if you know the worktree directory always stays inside of and at the same depth in the repository folder. And in the workflow I am currently experimenting with, that would always be the case, unless I was using slashes in my branch or worktree names, and changing the number of slashes because I was reorganizing. So that's trivial to fix. Even in that edge case where the depth changes, I'm not losing anything - either way I'd have to call either `git worktree move` or my alternative subcommand to move the worktree.
But relative paths in the repository's gitdir's `worktrees/{{ name }}/gitdir` seem to always be resolved relative to your current working directory instead of either of the two sensible options: relative to the repository gitdir or relative to the normal working directory. And this means there can be no relative path which Git would never misresolve, and in fact Git might routinely resolve it to the wrong location in some pretty typical cases, though if you're lucky your process would always be in the right directory when it actually matters.
I'm thinking that `git-worktree-mode` eventually becomes just one subcommand of a more fully-featured command.
In particular, I'm seeing a lot of value now in replacing `git worktree add`, to solve these two problems:
Git uses absolute paths for everything worktree-related internally. This normally doesn't matter but will blindside you with problems if you ever move the repo folder or any of the worktree folders. Recent `git` versions have `git worktree repair` to fix this, so that's not too bad, but it's still annoying.
`git worktree add foo` always creates a new `foo` branch if no local `foo` branch exists, even if a remote branch named `foo` exists. To get "normal" behavior for remote branches, like what `git checkout foo` does, you need to do `git worktree add foo foo`. If you forget that, it is annoying and non-obvious to fix.
3 notes · View notes