29

I have used git update-index --assume-unchanged on some files to keep my changes to them from being committed.

When using git stash in the repository, those changes are stashed along with any other outstanding changes. This is expected behaviour, however git stash pop doesn't bring them back, so the changes are just lost.

Anyone know how to either prevent the files with the assume unchanged bit from having their changes stashed? Alternatively perhaps you know how to make sure that any changes that are stashed against those files are at least brought back?

William Pursell
  • 204,365
  • 48
  • 270
  • 300
Stephen Emslie
  • 10,539
  • 9
  • 32
  • 28

2 Answers2

8

assume-unchanged is a performance hack, and represents a promise from you that the file has not changed. If you actually change the file all bets are off. You should either rearchitect your repo so that you don't commit these files (perhaps commit filename.sample and .gitignore filename) or play tricks with branches so that the files you do not want shared with the rest of the world are off on another branch or otherwise hidden.

I have seen/thought of four suggestions on how to hide these changes.

1: Use a smudge/clean filter to change the file to what you want on checkout and clean it on checkin. Ugly.

2: Create a local configuration branch as described in http://thomasrast.ch/git/local-config.html The critical thing to remember here is that you develop on the primary branch and merge onto the config branch for testing. Back out to the primary branch to change, push, etc.

3: Create a private development branch, make the change you never want shared, and then make a fake merge (git merge -s ours privatebranch). You can then develop and test on your private branch and the change you do not want shared should not be when you merge back, as long as the change is far away from your normal work. However, when you get new changes from upstream, you need to pull them directly from upstream into the private branch. You then merge from private back into master and push upstream from master. You must never merge from master back into private. Likewise, you must never rebase (well, possibly rebase -p would work, but no guarantees). These merge/rebase and where each must occur makes this less attractive.

4: Create a private development branch, make the change you never want shared, and then create a merge driver (see man gitattributes) which will refuse to merge the file in question from master to private or from private to master (probably by comparing the SHA of the file on the private branch to the various branch's SHAs and copying the previous value if it matches).

Seth Robertson
  • 30,608
  • 7
  • 64
  • 57
  • I gave the private development branch a go. I created a private branch, made a commit with my private changes, then switched back to the main branch and did a merge `-s ours`. When I merged the main branch into the private branch however, it overrode my changes – Casebash Nov 09 '11 at 04:50
  • @Casebash: You did not fully describe what was happening, but I'll make a guess and say that the main branch changed the file you changed. That will indeed cause those changes to be propagated into the private branch once you merge main into private. If you are also fully merged from private into main, you could `git checkout HEAD^ -- myfile` to get the older version and the merge -s ours again. The purpose of the -s ours to is prevent the change on private from getting into main. Nothing can stop new changes from main getting into private (unless that file was changed in a single commit). – Seth Robertson Nov 09 '11 at 15:33
  • @Casebash: Well, I said nothing but I just remembered a neat feature of git. You can define a custom merge driver which will refuse to make any change during merges. However, the merge driver would have to be branch aware. You don't want changes going into or out of private, but you *do* want them getting into main from origin/main. – Seth Robertson Nov 09 '11 at 15:58
  • I did fully describe it - I didn't make any other changes. The point of merge is to make branches the same - that is why pulling back into the private destroys the private changes – Casebash Nov 09 '11 at 20:42
  • @Casebash: Hmm. I see what you mean. I wasn't thinking of the "our" merge as a change, but clearly git does. I guess the only option there would be to pull private from upstream/master instead from the local master. But push from master back to upstream/master after merging from private. As long as you never --rebase (heresy!) everything will work. Tested this time. Still, that is pretty annoying. – Seth Robertson Nov 10 '11 at 18:34
  • 4
    So, you're saying `assume-unchanged` does not work for the only thing anyone actually uses it for? – BlueRaja - Danny Pflughoeft Dec 17 '13 at 17:40
0

This question is similar to Preserve git --assume-unchanged files between branch checkouts. There I proposed using a private branch with these changes, which I detail here http://blog.ericwoodruff.me/2013/02/git-private-branch-pattern.html.

Community
  • 1
  • 1
Eric Woodruff
  • 6,380
  • 3
  • 36
  • 33