Home > Software engineering >  How to contain diff between two local git branches
How to contain diff between two local git branches

Time:02-10

I have same working directory but often keeps switching between two branches whose git head is at different points and also different local changes. Without pushing the diff to remote repo is there a way to maintain/ restrict the changes and not overwrite it when switching from one branch to another branch. I am not sure if git would track locally in this way? Please help

Say i am on branch 1 made some changes i.e. diff1, didnot stash this. Now i want to switch to another branch 2, at this point git complains either to commit or stash changes (diff1)? I am asking if we can switch to branch 2 without having to stash/ discard/ commit diff1 changes? somehow switch to branch 2 and work on changes, now when issued git diff it should show diff2 but not diff1. Dont know if this is even possible.

CodePudding user response:

TL;DR

Your best bet is almost certainly git worktree.

Long

You have several wrong starting-point ideas, that you'll need to get rid of, before you can solve your basic problems here:

  • Git doesn't store changes in the first place. Git stores commits.
  • Git therefore doesn't push changes either. You push commits.
  • Commits don't go anywhere until you send them somewhere.
  • git stash itself makes commits; we'll see why in a moment.

You therefore need to know all about commits. For much more about this, see, e.g., my answer here. To cut to the chase, though, each commit's saved content is entirely read-only. You literally can't work on a commit without first copying that commit out to a work area.

The files you're modifying, in other words, are not in Git at all. They came out of Git earlier, and when you have them ready, you will put them back into Git. But right now they're just ordinary files that aren't in Git. Git can't save them if you wreck them, and that's why you—sometimes!—get:

error: Your local changes to the following files would be overwritten ...

It's because your files, in your working tree, will have to be destroyed (removed and replaced with other files) in order to switch to the other commit. Git has checked, and what's in these files isn't what's saved forever in the commit.

Switching from one commit to another involves replacing files in your working tree—sometimes! That's the source of the "sometimes" above. If you're switching between two very different commits, most files will need to be replaced. If you're switching between two very similar commits, only a few files will need to be replaced, and sometimes you'll be able to do it anyway (see Checkout another branch when there are uncommitted changes on the current branch).

Using git stash makes commits: this saves your work. The commits that git stash makes are on no branch, which has two side effects that people find desirable:

  • You can't see these commits easily.
  • You can move the effect of these commits to some other branch easily.

It has other side effects that people find undesirable, including the fact that you can't see these commits easily. That is, the first side effect is both boon and burden.

The long and short of it, though, is that if you wish to switch the current branch and therefore also the current commit in the (single) working tree, you must do something about / with any changes you have. That thing you do can be any one of the following, or anything else you can think of:

  • leave them and hope;
  • stash them for later;
  • commit them—much the same as stashing, except now you can see the commits;
  • eradicate them entirely, with the intent of reproducing them later.

Multiple working trees

The key phrase above is:

switch the current branch and therefore also the current commit in the (single) working tree

Until Git version 2.5, Git only offered one working tree per clone. So to get a second working tree, you had to clone again, or clone your clone (either method can work though cloning-again avoids the need to properly learn and understand references and refspecs). Git 2.5 added git worktree, though, and Git 2.15 finally fixed a pretty nasty bug with git worktree. So if your Git is at least 2.5, and preferably at least 2.15, you can use this method. (If your Git is older, consider upgrading.)

With git worktree add, you tell Git: I'd like to add another working tree and corresponding index / staging-area to this repository. You tell Git which branch should be checked out in this second working tree, and Git will check out that particular branch. There is a constraint here: each branch in each added working tree can be used only in that one working tree. (There is a good reason for this constraint; you can get around it by deleting the extra working trees, or changing the checked-out branches in them, but in general you should just work within the constraint until you're done.)

Since each added working tree is an added working tree, with its own index / staging-area, you can now simply cd into a different directory, and/or open an additional window or set of windows to work in/on the other branch. Because they are separate, the two separate working trees won't interfere with each other unless you do something to make that happen.

See the git worktree documentation for further details.

CodePudding user response:

Say i am on branch 1 made some changes i.e. diff1, didnot stash this. Now i want to switch to another branch 2, at this point git complains either to commit or stash changes (diff1)?

@torek's answer is great and gives a lot of the detail. The one thing I'd like to emphasize is that if you made changes that you didn't commit, then git has no way to know how to resolve those changes with changes on another branch. This happens when two branches makes different changes to the same line of code and is one reason that git complains in the situation you describe.

I am asking if we can switch to branch 2 without having to stash/ discard/ commit diff1 changes?

So the answer here should not be clear: no, you cannot switch branches without stashing, discarding, or committing your local, uncommitted changes. The message from git should make this clear.

  • Related