Hacker News new | past | comments | ask | show | jobs | submit login

Not sure this is something I need. One thing I do need though, maybe someone knows a solution:

Often I find myself maintaining a handful of "local" changes. I make some changes that only make sense in my local environment, that I don't want to push.

What I end up doing is maintaining these changes as a commit, committing on top of them, and using `git rebase -i` to periodically move them up. Then before I push, I have to temporarily rewind the branch to remove them, push, then cherry-pick them again.

It's all a bit awkward and I would love a tool that maintains a kind of "virtual branch" that isn't shown but is automatically re-based on top every time I make a commit, maybe letting me resolve conflicts or even telling me ahead of time if I've created one, before committing.

Someone must have already solved this, or am I doing it all wrong?




It sounds like a project structure issue where local environment config that shouldn't be tracked is (or a lack of optional additional config that could be specified locally). Or maybe I'm misunderstanding the sort of change you're talking about.


This is what I thought, too.

I generally try to have support for this in the application, using a `.local` config file override which is in .gitignore. If one person has this trouble, chances are the rest of the team does too, and making this change is usually less time than the team collectively spends messing with it in a week.

Sometimes there's an existing workflow everyone just accepts (project in a specific path; some dependency manually installed locally; specific HOSTS alias to the database server IP; etc) but so long as you don't break that while also making it better/easier, I've found it's usually accepted.


Specifically, the fix is usually:

* Rename the configuration file in the repository to add an `.example` suffix (preferably, to an empty `-local` file if includes exist)

* As part of the build system, copy all `.example` files to remove the suffix, but only if they don't already exist.


Stash?

That's what I do, in any case. If I have a few various small configurations I want to carry around, I stash them when I need to swap branches and then pop them off.

That way it's never in the history and there's none of that nonsense to deal with.


I do this all the time in almost any repo I work in. I usually just keep the difference as “junk” in my local work tree.

I never git commit -a anyway, my commits are always kinda prepared and meticulous.

I just live with the spurious diff and extra stashing. All alternatives seem to complicated. I do love the way Jetbrains IDEs manage changesets though. It is a big improvement over only (not) using git for this, but I rarely use their IDEs nowadays.


> Then before I push, I have to temporarily rewind the branch to remove them, push, then cherry-pick them again.

You do not necessarily need to modify and restore your branch head just to push in this case. If you have e.g. two temporary commits at the top of the branch, you can use e.g. "git push origin HEAD~2:master" to skip those commits when pushing.


ok that one's a cool tip


I think this tool would help that, because you'd stick your only-makes-sense-for-you changes on `my-eyes-only` branch; that branch would always be in your 'integration' commit, along with whatever other 1+ branch(es) you were working, and you'd just only push the latter.

That said even without GitButler you can improve it a bit: you can `git push <remote> HEAD^:<branch>` rather than 'temporarily rewinding the branch to remove them'. You could also consider just never committing it, stashing the changes if you really needed them out of the worktree, and if they're whole new files adding to `.gitignore`.


Oh and enable rebase.autostash config option to help with not committing them, so you can still rebase without constantly having to deal with them manually.


This is true. For the use case you're talking about, just sticking some changes in a semi-ignored virtual branch basically will do what you are talking about. :)


What you are describing sounds very much like a common situation when working downstream of an open source project. I believe (and agree) the commonly accepted solution are patch queues, for which a number of tools exist: Andrew Morton's patch scripts, quilt, mercurial queues, guilt, stgit, to name just a few.

As you describe, just maintaining a branch that regularly gets rebased onto the latest upstream using only git's inbuilt tools also works. I do that, it's a good enough solution when keeping the history of old branches by merging them into a "patch queue history" branch before rebasing so they don't get lost.

Yet, I feel a much better gui tool to support this workflow is both possible and desirable. I totally agree with the venerable schacon in that regard. So whenever I learn of a new git gui tool I get excited and hopeful.

I actually started a tool some 15 years ago, with the vague hope I could one day open source it, or at least show it around so that others can take the good ideas and run with them to implement in their tools. Unfortunately I never had enough time to move it forward beside my day job.

15 years ago I built atop mercurial queues with a Mac gui. Of course a proper tool should be built on top of a cross-platform gui and libgit2. I can't do much at the moment, but I still hope one day someone will build on my ideas or come up with better ones.


Not a complete solution to the more generic problem you described, but enough for me most of the time:

1. I try to arrange things in a way that I can keep my local changes in files that are not in the repo. For example: If your software loads a file from several places and the more specific one (current dir) wins over a more generic one ($HOME or /etc) you can try to keep a local one.

All these files end up being .gitignored from a place that is not in the repo itself and not shared: Either in the global .gitignore or .git/info/exclude. If the files don't have to be in a specific place I put them in a subdir called aux, which also contains a .gitignore with just an asterisk (*) on the first line. That way it never gets added and it doesn't leave a trace in any .gitignore outside of aux.

2. Files that are checked in but need local modifications are marked with `git update-index --assume-unchanged`


If you need a lot of local changes that you can't commit, then either your repository or your project (or both) are organized improperly. You must have committed files to git that should never be committed or you project doesn't allow you to adapt to the local environment without changing files committed to git.

For example, you may have hardcoded paths to tools and compilers, but in your local environment those tools have different paths. This is a problem with the project organization.

Another example, you may have something like VSCode settings file which somebody decided to commit to git, but those settings only make sense in his environment and not anybody else's environment.

Instead of searching for a workaround to these problems like virtual branches, you should push for fixing your project organization and you git repository.


I have the same problem, but I haven't found a convenient solution yet.

Though stated differently, it's exactly the same thing: https://stackoverflow.com/questions/76717374/how-do-i-keep-a...

A somewhat related but inexact match is when you want to ignore changes to some files (e.g. I sometimes vary some test code locally and don't really want that to be exposed to others) for which I found a convenient fix on SO and compiled into an answer https://stackoverflow.com/a/70075113/3858681


It depends on the kinds of changes you mean. The kinds of local changes I have are just env variables that allow the software to run locally a little bit differently than in the production environment. I'm able to do this by using a .env file and a library for my languages of choice that read a .env file if it's there, but use defaults that make sense for prod when it's not there. Then the .env file is gitignored so it doesn't make its way over to the production environment.

Each developer can modify their .env however they want without having to make any changes visible to git.


I also have this issue. What I do is work in a separate branch and cherry pick commits over to main then rebase.

I bet that what you describe could be implemented with stashes and scripts run on hooks, but that feels like fighting the tool too much. There's probably something we're missing?


I think those local changes should be treated as config that can be overriden in the local environment through a combination of files that are listed on .gitignore and environment variables.


Stacked Git (stg) will let you push and pop commits. Pop when publishing, push back when you need them again.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

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

Search: