MaMazav
MaMazav

Reputation: 1885

git checkout & git pull : Avoid intermediate file changes when executing

I'm surprised I couldn't find anything about that...

In short, my question is if is there a way to avoid the intermediate file changes between the following two commands, if after the following two commands the file content is exactly as was before?

git checkout dev
git pull

The motivation is (Solution that meets only one of the motivations is also better than nothing):

This is a very common scenario when I'm coming back from a feature branch to master after merging origin/feature into origin/dev using a remote source control server.

I would expect that performing git fetch origin dev before will solve this but it doesn't. Also I found some answers like this which talks about grouping the commands together for easiness, but didn't targetted the file-changes issue.

Upvotes: 16

Views: 19454

Answers (2)

Pau Fracés
Pau Fracés

Reputation: 1143

git fetch origin master:master

Replace master with the branch you want to update. (In the OP's scenario, it will be git fetch origin dev:dev)

This command only works for a fast-forward merge.

Once the local branch is updated with the remote changes you can switch to the desired branch without causing file changes.

References:

Upvotes: 14

torek
torek

Reputation: 487785

There's a way to do this, using git worktree add. Be sure your Git is at least 2.5 (so that it has git worktree) and preferably at least 2.15 (fixes a fairly severe bug with added worktrees; without the fix, an added worktree should not be used for more than about two weeks, in general).

Your IDE may be incompatible with git worktree add; I avoid IDEs so cannot say which ones cooperate with it, and which do not.

Assuming you have a Git version that supports added worktrees, use git worktree add to create your dev branch, and leave the main worktree on the master branch. Alternatively, use added work-tree for the main (master, or whatever) branch, and the main work-tree for the dev branch. Remember that Git enforces that each work-tree have a different branch checked-out.

Stop using git pull. (This is not strictly necessary, but I recommend it.)

To update your repository from the server, use git fetch—with no additional arguments—at any time, from either work-tree. This obtains any new commits they have that you don't, and updates your origin/* remote-tracking names.

To update your master branch, enter the master-branch work-tree and, on the command line, run git merge or git merge origin/master. (Run git fetch first, if you have not done so recently, so as to have an up-to-date origin/master.)

To update your dev branch, enter the dev-branch work-tree and, on the command line, run git merge or git merge origin/dev. As before, if you have not run git fetch recently, you may want to do that first so that your origin/master is up to date.

Your IDE may or may not be able to achieve what the command line does, here. Depending on the IDE, perhaps it will work to run two copies of it, one in each work-tree.

Remember, all git pull does is run git fetch and then git merge (or git fetch and then git rebase). It's the git checkout that is messing with the time-stamps on your work-tree files. Git doesn't really use or need the work-tree: that's for you. Running git checkout replaces the files in the work-tree with those from the other commit, while also replacing the files in the index; the index copies are the ones Git uses and cares about.

Git replaces the work-tree files because it assumes you need the ones from the branch you are switching-to. Switching back, of course, updates those work-tree files yet again. So now various files have been updated twice, and need rebuilding.


When you add a new work-tree, Git actually adds a group of three items:

  • a new HEAD for the new work-tree, to remember what commit and/or branch are the current ones in the new work-tree;
  • an index for the new work-tree, that Git uses to store Git's files for the next commit you might make; and
  • the new work-tree itself, for you to see and work with the files.

This work-tree is simply a directory (or folder) that is outside the main repository work-tree. For instance if your main repository is in ~/work/project you could move it to ~/work/project/main and create ~/work/project/dev to hold the dev-branch work-tree.

Fundamentally, though, the problem is simple: When you use git checkout, git replaces both index and work-tree contents as needed. So you need to stop using git checkout. If you need both work-trees, make two separate work-trees.


If your Git is too old to support work-trees, make two clones. Everything else works the same except, of course, that the two clones do not share branches.

Upvotes: 1

Related Questions