Hacker News new | past | comments | ask | show | jobs | submit login
Git Worktrees and GitButler (gitbutler.com)
104 points by chmaynard 6 months ago | hide | past | favorite | 80 comments



I've started using worktrees recently and I have nothing but praise for it. It's especially useful to me because I work on multiple features and want to reduce friction from context switching. I basically have a structure like `/worktrees/<project>/<worktree>`. I use it alongside direnv and have my .envrc in the top-level project. That essentially allows me to set up project-specific environments for all of my worktrees. This works neatly with emacs projectile mode and lets me switch between different projects/features seamlessly. My head feels a lot lighter not having to worry about my git branch state, stashing changes, and all that jazz. I think it's a great tool to have in your repertoire and to use depending on your needs.


this is what I do as well but my structure is `~/git/<project>/<worktree>` for the worktrees and a bare git repo is stored in `~/git/<project>/.git`.

The workflow I do is

1. git clone https://path.to/repo.git

2. mv repo/.git repo.git && rm -rf ./repo && mkdir repo && mv repo.git repo/.git && cd repo

3. git config --bool core.bare true

Now you can just create worktrees in the root of the git repo.

This has the advantage that the `~/git/<project>` directory is still understood as root of the git repo and the worktrees are never checked out inside the working tree directory.


Why not `git clone --bare`?


I've tried this and it seems to be working fine.

git clone --bare https://path.to/repo.git

mv repo.git .git

now we can create worktrees in the same folder.


fwiw you can actually one line that

> git clone --bare https://path.to/repo.git .git


You can bare clone and it works fine. This is in part just habit from converting existing repos into bare + worktree repos.


The only problem I've ever had with work trees is my own lack of discipline; even with one directory per branch I seem to switch branches within each checkout without thinking and so make me life needlessly hard>:( Perhaps I should write a shell function to outright disallow switching branches...


I do that to but for the many stable branches of OpenStack/Ceph/etc that I’m working on at once (working on the distro/backporting side often back porting patches 3-8 releases). It’s great.


I use worktrees very rarely. For instance, if I'm trying to figure out some very hard to reproduce bug that disappeared between one revision and another and I need to examine the code. I can't just bisect if the feature set or interfaces are different so I need both versions of the code. Sometimes I cherry-pick around to restore some similarity.

But for this two-patch flow, I'm just going to use two branches.


Being able to explore code from another revision in your regular editor side by side with your other branch (two editor instances) is a big plus of worktrees. Maybe it wouldn't work if you use some heavyweight editor like Visual Studio or Eclipse or if your project is massive and IDE intelligence features take up a lot of RAM, but for lightweight editors, small-medium projects it works great.

I personally use it all the time on longer lived projects. Stashing/unstashing is fine, but I like really like the flexibility of just being able to switch over to another branch to fix something, review a PR, or anything else with zero mental overhead of keeping track of stashed work.


The thing that annoys me about worktrees is that you can't have two checked out to the same commit at the same time [0], which can be inconvenient when I forget about one that I had open a few days ago. This also breaks the feeling of isolation, since the issue doesn't exist if I do a fresh `git clone` to another directory, so it begs the question of what fragility is present in worktrees that isn't in a fresh clone.

In other words, I wouldn't feel safe doing weird Git operations in a worktree, so why use one in the first place? If I want a true throwaway repo, I'll just re-clone in another directory (and make sure to remove the remote, to be extra safe in case I accidentally push).

Also, git worktree requires me to make a new directory anyway! So why would I not just put a fresh clone in there? To save a few megabytes of the .git index?

[0] https://stackoverflow.com/a/39668520


You can do this. You just need to use --detach.

When you check out a branch, your working directory is expected to be in sync with it. Internally the HEAD points to the branch which then points at the commit. When you make changes on one worktree, in general it doesn't update the other worktrees.

So if you change the reference that the branch is pointing at, when you look inside the other worktree that points to that branch, it has no way of knowing it was initially looking at a different commit and it just thinks that the diff between the current head of that branch and your current working directory is a bunch of uncommitted changes.

If you use --detach or refer directly to the commit instead you get the behavior that is expected which is that it points to the commit itself and not the branch (which then points to the commit).

> Also, git worktree requires me to make a new directory anyway! So why would I not just put a fresh clone in there? To save a few megabytes of the .git index?

The problem is that not all repos are small and often it's easier to just do things in one repo than to need to push everything up and pull it down to move between multiple repos.

Also not all repos are small. The linux repo (which if you are working in the higher spec side of embedded software you probably will be using with multiple different downstreams) is at least a gigabyte in size nowadays. I like having the whole repo when I can because it makes looking for stuff locally easier but I don't want to lug around multiple copies of that repo if I can avoid it.


They can absolutely be checked out to the same commit. They cannot be checked out to the same local branch. But checking out to the same SHA, or even the same remote branch (which, really, is just another name for a given SHA) is just fine.

I have two workflows heavily benefitting from worktrees. The first is simple enough...code archeology. I want to do it without disturbing my working tree. Yes, this could have also been done with a separate clone, but I'd have to fetch in that clone, and that's just extra keystrokes.

The second is that I like to have a "synthesis" worktree...one that includes PRs I'm reviewing and ones I'm creating. Both benefit from my regularly building and using them (e.g., I might incidentally find bugs through usage I otherwise missed through testing or code-reading, or I might spot pending integration problems). I don't want multiple build locations...I want to run everything in one build.

But when I've finished developing a PR, need to create a clean version of it from the master branch. In my secondary worktree, I can just cherry-pick commits from my synthesis worktree to produce a clean branch to push. I could do this in the synthesis worktree, too, but at the cost of almost certainly forcing a complete rebuild. In a second clone, I'd have to create patch files because the clone wouldn't have access to the commit objects for cherry-picking.


You can make a temporary branch if you want an identical copy of a revision. For example, `git checkout feature-x` (on worktree 1), then `git checkout -b feature-x-temp feature-x` (on worktree 2).

I've never had any issues with worktrees after heavy and extensive worktree usage since 2017. I use it regularly on big projects. The only time I had an issue with git was actually on a small non-worktree repo after 10 years of using git. The .git/ metadata got corrupted somehow, never understood why or how.

When you have a worktree based workflow, you're getting the benefit of a single .git/ database managing them. Whereas if you have multiple standalone clones, you have to manually keep them up to date. With worktrees doing a `git fetch` will ensure all worktrees are able to do git operations on the most update to date git data. Whereas separate clones means you need to do N git fetches.

Saving a few megabytes literally doesn't matter. Your project dependencies will likely use up tens if not hundreds of megabytes when you install them (pip packages, node modules, etc). Disk space is never really an issue anymore is it? Disks are hundreds of GBs now even on low end machines. I probably have multiple GBs of redundant disk usage because of my worktrees, but the convenience is well worth it IMO.


I find this very annoying. I don't know if this is the right thing or not, but my workflow for starting new work is "git checkout master; git pull; git checkout -b new_work". This is all fun and games until you have a worktree that's sitting at master. Now you have to figure out where that is, chdir there, and update that branch from the remote. It's actually extremely annoying.

Maybe there is "git update master from remote and throw away my local changes because if i committed something there that was a mistake". But probably not, sadly, because technically the "git pull" operation to pull origin/master into the local tracking branch master updates the working copy where master is checked out, and that's what worktree is trying to avoid (changing a directory you're not in). I guess "git pull; git checkout -b new_branch remotes/origin/master" is what I should write, but that's more bytes to type.


I get around this by having "wt-" (wt-1, wt-2, etc) branches that act as my main/master branch per work tree.

As long as you set the upstream to master, it works fine, you can pull in upstream main/master changes without issue. It does mean you have these "wt-" branches, but it works well enough for me, never got in my way or caused me to stop using worktrees.

My workflow is like this: For each worktree I add, checkout a new branch, wt-N, with it's upstream set to main/master. If I need to checkout some other branch in a worktree, do it, finish up, check out wt-N again, git pull to bring it up to date with upstream. Leaving idle worktrees on a "wt-" branch so I don't have the issue of "branch X is already checked out out worktree Y"


  git fetch origin
  git checkout -b new_work origin/master
Git pull is essentially git fetch + merge. You don't have to update your local master branch to check out a new branch based on it.


just a minor nit but you don't even need to do `remotes/origin/master`, just `origin/master`.

Alternatively you could do `git switch -c new_work && git pull -f origin master` which will create a new branch (you could use `git checkout -b` as well but like you said, more bytes to type) and then force pull from master on origin into the current branch (which is now your new branch) replacing the history with origin/master.


> The thing that annoys me about worktrees is that you can't have two checked out to the same commit at the same time

Checking out the same commit is fine. You just can’t checkout the same branch.

This is not a problem for me because I either use detached head (if say I’m going to build from some commit) or restrict branches to certain worktrees naturally (if I am backporting to `old-version` on a worktree then... it’s not like that backport branch is ever going to be relevant in my main worktree where I do most of my work).


I used to use it myself. Not too much of problem. I just didn't use it enough to warrant use. Was quite straightforward to just switch up. But I shall try it again and see.


I use to work at a company whose product had multiple versions of Java over its existence (literally think from Java 5 to Java 18), depending on the major product support versions (yes we had clients still on 1.0 system from the early 2000s, they were mostly regional banks).

Worktrees made working on that monolith easier to do my types of tasks (updating tests that were specific to the UI team I was on, also the only person willing to touch java code).

It sounds kinda backwards, but if you have to support multiple versions of a product that still brings in hundreds of millions in revenue it's nice to use git worktree to basically check out different versions of your product in time.


The first big thread on GitButler (recent) left me scratching my head. All the material with jargon like “virtual branches” just left me confused. It was like jumping into a how-to on why choose a Ferrari without first understanding what a car is. This clears things up nicely.

I mostly use worktrees for very separate things. Like: long-running build, way old or way new versions of the app. Then it doesn’t make sense to mix-and-match virtual branches. So when I want to build the app for deployment I don’t want to worry about whatever other changes getting in the way. Git worktrees doesn’t solve the same problem as what GitButler does. Worktrees is a streamlined way of the manual separate-clone workflow for the same repository. (Technically they are all distinct repositories once you clone them but ya know.)

I do have use for separate-from-branch files. Like notes to myself and test scripts that aren’t going into the branch. Crucially these files have nothing to do with the main work: the files themselves are not involved, so there can never be merge conflicts.

This GitButler workflow makes sense for things that (1) won’t cause merge conflicts and (2) which won’t step on each others’ toes. The example about a translation and code change is nice. Doing a translation at the same time as a code change is not likely to “break the build”.


For reference & context, I believe (I hope!) this is the "first big thread on GitButler":

https://news.ycombinator.com/item?id=39356042


https://news.ycombinator.com/item?id=39357068

The submitter unhelpfully didn’t mention the name in the title.


> Then we go to our GitButler UI and we see that an anonymous virtual branch has been automatically created, because it saw new changes. We can just drag one of the files into a new virtual branch lane, then commit and push both at the same time.

This is where he lost me, do I now need an UI to use git? ridiculous


> do I now need an UI to use git

You and I don't - but, judging by what I've seen from coworkers, we are in the minority.


I've recently read about worktrees and currently trying to incorporate it in my work routine. For NodeJS applications, it seems we need to create a soft link to point to the node_modules folder in "main" worktree in all worktrees. Otherwise we need to do a npm install in each of the worktree, and knowing how big the node_modules folder can be, a lot of disk space and time is wasted.


Worktrees have been a massive savior for me when using Rider (which is all that I use them for). Previously, switching branches would cause the cache to become out-of-date; which would be fine if amending it didn't break 80% of the time (causing spurious code issues etc.).

It works just fine with Sublime Merge, so long as you add the worktree as the repo - not the bare repo. I do wish there was better integration.


Is there now native control for Worktrees with Rider (or any of the JB Tools for that matter)?

I tried Worktrees a couple of years ago but not having any integration with them with Rider led me to walk away.


I'm not sure unfortunately. I vastly prefer directory-centric SCM over project-centric.


Worktrees are pretty great but I don't understand why I can't have the same branch checked out on two worktrees? I get why committing to a branch checked out elsewhere might be bad, but in that case, just prevent me from committing, like "you can't commit because the branch is checked out elsewhere - maybe create a new branch".


You can absolutely check it out in multiple places. You get a warning because the behavior is unintuitive.

If you want to force it to do it anyways you just use -f/--force.

When you check out a branch, the expectation is that the working tree is in sync with the current head commit. If you check out the same branch in multiple places, then if you commit on worktree a, worktree b won't say that it's still on the old commit, it'll just say that the diff between the current head and the contents of worktree b's working directory are a bunch of uncommitted changes. That's why it's unintuitive.

This is clearly not the intended behavior for most users when they want to check out the same branch in multiple places. They want to check out a given commit that happens to be the head of the current branch in multiple places. To do that you use --detach so that the worktree head points to the commit rather than the branch itself.


In general, `git` seems to fight changing checked out code. You can't push refs to a repo on a checked out branch, for example.


For a lot of projects, I have 2 worktrees, where one is for my own work on the project, and the other one is for reviewing other people's code.

That means that I can easily do a review (I like having the code open in my IDE during a review), without having to stash my own work.


I didn't know about worktrees, sounds a lot like bazaar used to do branches which I always considered much more convenient than gits way. I think I start using it straight away.

Cheers Jochen


I am struggling to appreciate how this is _not_ a completely flawed workflow. Are many teams doing this? What is the workflow like that benefits from this? What's the "shit not _that_ branch":commit ratio?


Personally this sounds completely reasonable to me (especially with lazygit)

> You can stash everything, create a new branch, switch to it, fix the bug, commit and push it, then switch back to what you were working on.

Also comfortable with fixing the bug on my current branch, leaving it there to validate as I complete the other stuff, then later pull commits out to new branches to create atomic PRs. Assuming the bug can wait that is, otherwise yep off to a new branch, and no amount of git magic prevents an interruption from being disruptive.

I know worktrees are a thing but I feel like the branching model is enough complexity to both be useful and remember. No problem if people want to use a more complex workflow with a GUI, this is for them, not for me.


We’re not yet using git, but we have one repository with multiple branches, one for each released version (on-prem software, not a service run). We are in regular active development of ~3 branches at a time. Most developers dealing with this will have multiple clones checked out rather than switch branches in the same clone. The reason for doing so is we often make significant project structural changes in each release, and the act of switching branches updating thousands of files and lots of structural changes often causes most IDEs to combust. Pointing the IDE to a different cloned workspace works much more smoothly. After switching to git I anticipate it will include our own guides for using worktrees for such a purpose.


What part exactly? The worktrees?

If you're just talking worktrees, the benefit is what it says on the tin, multiple parallel working directories. They're a nice to have, not world-changing or anything.

The example in the article is contrived to sell a separate kind of workflow tool in the product he's building. I don't use worktrees like that.

My use case is heretical software development, but sometimes I work with projects that take a long time to build. And even longer to test. Worktrees let me minimize the amount of rebuilding when switching branches, or kick off a full test run and go work in another branch.


Another way to look at this, is that a working copy is a projection of the state of a repository at a particular commit. If you are working on or with a tool that utilizes the repository contents to drive it, then you can expose multiple instances or versions of the tool from those projections, while leveraging a shared content cache and upstream configuration.

For example, let's say you are working on a static site (this is just an example). You can have a web server running that is serving the main worktree from https://mysite.local/, and any worktrees from https://mysite.local/~[worktree]/. Then, if you want to make a particular branch available for someone to review in their browser to provide feedback, you can direct them to the worktree URL while you continue doing other work either in your main branch, or on other branches altogether.


>Let's take an example. Let's say you are working on a feature. Your boss interrupts you (, bosses, right?) and says "we need this bug fixed". Or maybe you just notice the bug as you're working. Whatever it is, you need to switch contexts while in the middle of something. Now you have a few options.

- You can fix the bug and commit it into your feature branch and try to get them both deployed together.

- You can stash everything, create a new branch, switch to it, fix the bug, commit and push it, then switch back to what you were working on.

- You could locally clone the repository to a new directory and work on the other branch there, then push it back into the main one and then push from there back upstream.

--

What?

Why couldn't you, like, create another branch off of main, switch to that, and fix the bug there, then resume working on your feature branch?

Then when one of the two (bugfix or feature branch) is merged into main, you rebase main into the other.


I've been where OP is. For me it's because, for whatever reason, I don't want to commit my shitty in progress work right now to go work on this interrupt. And if I stash it, I will likely forget I did that, and waste time looking for it again.

Worktrees are a different way of managing multiple branches in flight. They're not hard to use, and using them doesn't imply any incompetency with git. They are likely being used to cope with another kind of problem.


There's another case where worktrees are great, whether or not you are compensating for other problems. If your project's build takes forever, but incremental builds are relatively fast, worktrees are a good way to preserve build state on the file system between branch switches.


>worktrees are a good way to preserve build state on the file system between branch switches.

Why would you ever have build artifacts, incremental or not, as part of your code repo?


It’s probably not part of their repo, but exists alongside, possibly gitignored. Either way in the same workspace the IDE will have to invalidate a lot of it when you switch, and again so when switching back. Separate clones, or worktrees, mean they don’t get invalidated and your IDE just sees them as a separate project altogether, each with its own cache, regardless of where that cache exists.


I picked up my git workflow from a very commit-centric workplace.

Instead of stashing or anything like that we would commit with the text "WIP". Every time we had a stable point, we would make a "WIP" commit and then continue, giving us a good point to revert to if the next steps don't work.

If someone interrupts me I would make a WIP commit and then revert it and then make the change they're asking about.

Later on we would squash the WIP commits and make real commits out of the changes.

Another nice thing about this workflow is that everything goes into the reflog.


This is the way. Just commit. You can undo it later or whatever, but at least it’s there.

Just one concept instead of (1) commits (2) stash (3) oh these changes, eh, I don’t know what to do with them... let’s think about it after lunch.


There are many legitimate use cases for multiple worktrees.

Here's one example:

I'm working on a trunk-based project, and I am upgrading a core framework like Angular or Django. That's a fairly intrusive change that involves modifying some untracked on-disk artifacts, like node_modules/ and package lockfiles. Switching branches doesn't help me manage those artifacts, and might require a full teardown and rebuild of my dev environment each switch. Even if I maintain a meticulous commit history and never have uncommitted "WIP stuff" that I need to stash, switching from my branch to fix a bug in the main branch could be annoying and intrusive just because of the dev environment. This is a great case for a separate worktree.


Yep, just added similar thoughts myself.


Why not commit what you have and ammend / rebase it later?


> For me it's because, for whatever reason, I don't want to commit my shitty in progress work right now

This is kind-of the million dollar question, though, I think? What would such a reason be?

(I ask from a perspective of genuine curiosity, not of implying that you're wrong to have them)


I don’t want to pollute a real branch with crap. I know how to rewrite history getting rid of it all, but I’d rather not. I prefer a bright line between tested, quality work with messages ready for review, and whatever I happened to be in the middle of (that I may or may not decide to abandon later).


Fair enough!

Just for the purposes of comparison - my own "bright line between [good and bad]" is "does the commit message just contain 'WIP', or is it actually fully written-out?" - but I can see that "is the work committed or not?" also works. Thanks for explaining!


What worries me about WIP commits is that dropping them via rebase -i might not be trivial if quality commits later depend on them.


Certainly! That's (one reason) why I'd _never_ drop a commit while doing `rebase -i` - just squash everything into a single (well-written) commit once it's ready to be reviewed!

On some _very_ rare occasions, I might find that, by the time I've gotten the change to a reviewable state, it's actually too large to be meaningfully reviewed in one go, in which case I'll go back and retroactively (re-)implement it reviewable-chunk-by-reviewable-chunk (on a different branch), and get each of them reviewed and merged in turn. But, 99% of the time, I simply:

* use WIP commits as "checkpoints" along the way while implementing

* get to a minimal mergable change

* use `rebase -i` to squash everything into a single, well-written, reviewable commit

* rinse and repeat


Completely agreed, this is pretty basic git that I would expect experienced developers to have down. This isn’t even a UI vs CLI argument, it’s the same idea in either case.

I’ll keep an open mind, but if you’re going to shake up a workflow as solid and well understood as git, you better have a damn good offering.


This is word for word what I was about to write. Totally agree as I had a very puzzled face when that option didn’t appear in the list. And even more puzzled when (what I thought was the throwaway flippant idea of) ‘cloning the repo into another folder’ was in the list. I can safely say, I’ve never done this and can’t think of a scenario where I would need to.


How is it different from the second bullet point? Except the second bullet point is more specific in that it says what to do with uncommitted changes.


>How is it different from the second bullet point?

How "cloning the repo on a different folder on the same machine just to work on a bug fix" is different from the main way Git is supposed to be used (creating a new branch for the bug fix and working there, then checking out your feature branch again)?

In that it doesn't make sense.

They might as well go full 1980s style "codebase_1/ codebase_2/ codebase_3/ codebase_3.bak/" and so on copies, and skip code management altogether...


That's the third bullet point. I was talking about this one:

> You can stash everything, create a new branch, switch to it, fix the bug, commit and push it, then switch back to what you were working on.

OP said this (you and a few others reiterated or agreed with it)

> Why couldn't you, like, create another branch off of main, switch to that, and fix the bug there, then resume working on your feature branch?

I can't see the difference. Seeing them side by side they're virtually identical except the blog author specified stashing!


I don't particularly care either way but how is that meaningfully different from option 2? You need to do something with your WIP in either case before switching to the new branch.


Well, stashing is ok for short term context switch, but it's not that organized or neat.

You're supposed to be working in a feature branch when your were given the bug to fix. Would you not have commited (or, worse, pushed) anything to it already? Most times you already have, so it's not like stashing your latest changes and getting to the latest state of the feature branch is neutral.

Plus, what big benefit would stashing have, since you'll still need to create a separate bugfix branch to create the bugfix PR off anyway? If you get to context switch while you were working on my-feature-branch, you still need to create my-bugfix-branch and push the fix from that, no?

Besides nobody guarantees you ahead of time that the bug will just be solved fast and they get to return to working on the feature pronto. So a bugfix branch makes more sense than a stash, which is more of a short term thing.

Just making a bugfix branch is neater.


You might not be in a position to commit. You could commit just what you have, make a bugfix branch, and then when you return to your original branch do a git reset later back to the uncommitted state. It just isn't that neat.


“Not in a position to commit” in Git makes as much sense as “not in a position to save the file” (in your editor) in 2024. Git is in a sense a primitive tool: only about snapshotting, not about high-falutin things like “passes the tests”, “is okay with Bob”, and so on. It’s just about tracking state.

(Again this is what git-reset(1) and friends are for)


> Git is in a sense a primitive tool: only about snapshotting, not about high-falutin things like “passes the tests”, “is okay with Bob”, and so on. It’s just about tracking state.

Git might be, but how many people want to use git is to provide useful commit histories, both for any reviewers at the time and any code spelunkers 10 years into the future. Having a tool that tries to make that easier isn't a bad idea.


My comment was totally unclear. By primitive I mean that it scales from very primitive operations (just snapshot) to supporting high-level workflows (refactoring, testing, verifying).

And by primitive I mean that I want to be able to commit whenever I feel like I want a snapshot. For any reason. Not hindered by concepts like does-it-build. That’s the low level. Then at the higher level are things like “public history” and “tested history”. That’s facilitated by the low/mid-level history rewriting tools.

Some people I know use Intellij’s “shelve” feature or whatever it is called. Interestingly it does provide some features that Git does not seem to have—and overlaps with GitButler—but it’s own bespoke thing, not integrated with Git.

And using these extra concepts on top of (or under?) Git doesn’t make sense for my workflow. Because the VCS is already there. So I don’t need to think about if I’m ready-to-commit—just make a WIP or a TEST commit, maybe discard later or maybe rewrite them.

For me, Git covers everything from snapshotting some private notes I have on the work that I’m currently doing to making a nice:

> useful commit [history], both for any reviewers at the time and any code spelunkers 10 years into the future.

It provides that whole range.


> And using these extra concepts on top of (or under?) Git doesn’t make sense for my workflow

I think this is the key comment - that might be true, but I don't see a real criticism of making tools for not-avgcorrection to facilitate their workflows better. I agree things can be done in Git. I disagree that they must be done in Git.


>You might not be in a position to commit

So? That's what amend and/or squash is for. So that you don't need to be in some "perfect" condition to commit. Or you can do a soft git reset as you say.

But sure, even git stash would make more sense than worktrees for the TFA scenario I quoted.


> You need to do something with your WIP in either case

Why not just commit it?


Sure. In terms of steps taken it's not particularly different though. Stash at the start and pop at the end vs commit at the start and reset at the end, right?

I mean, if it's not a problem to do that (and I don't find either option a problem personally) then fine, but it doesn't seem like it's a "better" option except in some small cases (like forgetting you stashed).


I'm so confused. Blog author said this:

> You can stash everything, create a new branch, switch to it, fix the bug, commit and push it, then switch back to what you were working on.

And OP said this (snarkily)

> Why couldn't you, like, create another branch off of main, switch to that, and fix the bug there, then resume working on your feature branch?

They're the same except the blog author was more specific!


You don’t have to interpret it as you-always-do-this. Just sometimes you want a worktree (or clone): maybe the bug fix needs to be applied to an old, old release which would invalidate all the indexes in your project. So then you can make a worktree so that your main worktree is left in peace.

But is it overkill for some fast translation fixes? Yeah, probably:)


If you want to run some time-consuming tests prior to pushing your bug fix it's convenient to run those in your separate worktree. You can continue working on your original branch while the tests run.


The article starts out by talking about the built in git worktree command which will do this for you, and is built into git already.[1]

The question is, if that exists why are the virtual trees meaningfully different?

[1] https://git-scm.com/docs/git-worktree


> Why couldn't you, like, create another branch off of main, switch to that, and fix the bug there, then resume working on your feature branch?

I mean, that's option 2 of what you're quoting, and is generally my preferred option. That said, there are cases where it breaks down and I end up wanting worktrees or independent clones, generally involving ≈`.gitignore`d local data:

• A newly created bugfixing branch may take awhile (minutes? hours?) for me to build. I can either go on a coffee break while waiting for it (since I can't very well test my ability to reproduce the bug, nor verify my bugfixes work, without having said branch in a compiling state), or I can have said build occur in a secondary worktree - and continue working on my original task in my primary worktree while waiting for it to build.

• If I've got a lot of `.gitignore`d config file tweaks related to my major feature work / profiling / debugging / ???, I might not want to bring those over to my bugfixing session. `git stash push --all` is an option, but that will get build artifacts - which will take awhile to stash - not just my local config files. A fun ancedote: I once wasted an hour failing to reproduce a game's audio crash because a local `user.ini` file had the entire audio system disabled via feature flag. (I now prefer setting the volume to 0 instead.)

• I do a bunch of porting and cross-platform abstraction stuff, which makes my build times even worse than usual by having to repeat builds N times. I might not want to invalidate by main build cache for all that, when my bugfixing branch might only reasonably need local testing on 1 platform, and gain next to no benefit from the previous cache as is (depending on how far diverged the branch I was working from and the branch where the bugfix should occur are.)


>I mean, that's option 2 of what you're quoting,

No, option 2 is to stash.

Their three weird options are:

(a) fix the bug on the feature branch and "try to get them both deployed together"

(b) git stash, fix the bug in a new branch, come back

(c) locally clone the repository

At least (b) is somewhat sane, but it's still weird that the even more code-managementy option of "commit your halfway feature work/create new branch for the bugfix/come back to the feature and amend/squash/soft reset" isn't even mentioned.

Your cases are more involved than the contrived scenario you give, where their weird options don't make sense.


I think that you (like me) prefer to use commits in places where many others prefer to stash. Personally I think the stash command is too primitive to bother with for all things except maybe an push+pop that happens within half a minute. Anything more and I risk forgetting about it. A WIP commit however is just there, on the branch, for me to deal with however I want later.

I don’t want to fiddle with dropping the stash one too many times, forgetting what they were about and so on. Merge conflicts because I didn’t pop before resuming..

It’s just a mostly useless additional “thing”.


Amendment: I just found out that I do have at least one use for git-stash, which is when I am stuck in the middle of a rebase somewhere and made an edit intended for another point (commit).


> "commit your halfway feature work/.../come back to the feature and amend/squash/soft reset"

...this is just by-hand stashing with alternative commands and extra "WIP" commit messages.

Which, uh, is admittedly an option. One that won't easily preserve your index independently from your working tree - awkward if you're in the middle of painstakingly separating out changes to add to the next commit with `git add -p` - and one that risks "WIP" commits ending up in your tree... but it is an option.


IMO you don’t need anything more than commits. The by-hand is writing WIP in the commit message. If that is an inconvenience then I’ll make a commit alias.

The index + commits is flexible enough. The stash concept is not needed for me.

See: https://news.ycombinator.com/item?id=39606525




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: