Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do git update-index --assume-unchanged rules propagate to clients on pull?

Tags:

git

gitignore

There are instances where I can't use a .gitignore file, otherwise, on git push, critical files are purged from the remote. In these cases, I apply git update-index --assume-unchanged <file> to the files that I want to ignore.

After applying the assume-unchanged rules and calling git push, will these rules be attached to the remote branch so that all subsequent pulls (from other clients) will inherit them? Or, must these clients also run the git update-index --assume-unchanged <file> commands individually at their machines?

If the commands are not inherited -- has anybody written a server hook for this before? Instead of mandating that all current and future clients safeguard against it?

like image 835
Jordan Arseno Avatar asked Sep 02 '13 10:09

Jordan Arseno


People also ask

What does git update index do?

Runs git update-index itself on the paths whose index entries are different from those from the HEAD commit. Restores the unmerged or needs updating state of a file during a merge if it was cleared by accident.

What is refresh index in git?

git/index changed by windows. So it can only refresh the index and replace the . git/index file, which makes the next git status super fast and git status in windows very slow (because the windows system will refresh the index file again).


1 Answers

The index is local to your workstation, any changes you make there do not propagate to other clones of the same remote.

(updated, after question was updated)

The .gitignore file

There are instances where I can't use a .gitignore file, otherwise, on git push, critical files are purged from the remote.

This is not true. The git ignore file does not affect files that are already tracked in the repository. If you add a file to .gitignore after it has been committed, it'll stay inside the repository; it will not be purged. In fact, it behaves pretty much as if it weren't ignored at all.

You can easily check this in a temporary repository:

$ mkdir -p /tmp/repo $ cd /tmp/repo $ git init Initialized empty Git repository in /tmp/repo/.git/ $ echo red > a.txt $ git commit -am '1'  1 file changed, 1 insertion(+)  create mode 100644 a.txt $ echo a.txt > .gitignore $ echo b.txt >> .gitignore $ git commit -am '2'  1 file changed, 2 insertions(+)  create mode 100644 .gitignore 

The repository now contains two files: a.txt and .gitignore. Both behave normally, which you can see when you clone it:

$ cd .. $ git clone file://repo repo2 $ ls -A repo2 .git       .gitignore a.txt $ cd repo 

If we modify both ignored files and request git status, we'll see that a.txt is seen as modified, despite having been gitignored. We can add and commit it as normal; in fact, if you add an tracked file to gitignore, it behaves pretty much like it's not in gitignore at all.

$ echo green > a.txt $ echo blue > b.txt $ git status --short  M a.txt $ git add a.txt 

The b.txt file is different, because it was ignored before git started tracking it. This file will not normally make it into the repository, but we can force it if we want to.

$ git add b.txt The following paths are ignored by one of your .gitignore files: b.txt Use -f if you really want to add them. fatal: no files added $ git add -f b.txt 

Issuing git commit now commits two files that have both been git ignored:

$ git commit -m '3'  2 files changed, 1 insertion(+), 1 deletion(-)  create mode 100644 b.txt 

Long story short, think of git ignore rules as guidelines :-)

Propagating assume-unchanged

After applying the assume-unchanged rules and calling git push, will these rules be attached to the remote branch so that all subsequent pulls (from other clients) will inherit them? Or, must these clients also run the git update-index --assume-unchanged commands individually at their machines?

The latter. Closest you can get is add a shell script to the repository that makes the changes for you.

The server hook?

If the commands are not inherited -- has anybody written a server hook for this before? Instead of mandating that all current and future clients safeguard against it?

If your aim is to write a server hook that removes the critical files as if they weren't part of the push at all, that's not possible. Git push deals primarily with commit objects (and refs). Their dependent objects, like trees and blobs, are transferred as needed, subject to reachability from a commit. What it boils down to is that, if it's not committed, you can't push it to a remote (that's an oversimplification, but it holds true for the files in the repository). In addition, git commits are cryptographically guarded. You can't change a commit without changing its commit hash, and if you change the commit hash, you basically have a different, new commit (that may happen to have the same diff as the old one).

This means that the server can't rewrite commits; at least not without seriously confusing the client that did the push (which will still have a copy of the old commit objects).

What you can do is write a post-receive hook that refuses the commits if they contain the files you don't want to have updated. This doesn't really solve your problem, because if you have trouble explaining git commit --assume-unchanged to your coworkers, then you'll likely have even more trouble explaining how they can use interactive rebase to recreate their commits without the undesirable files in them.

Long story short, I think chasing everybody to keep using assume-unchanged (maybe combined with a post-receive hook) is your least bad choice if you're dealing with files that should be committed once and never thereafter, like you have now.

A possible work-around

Your life would become a whole lot easier if you can keep these files out of git in their entirety. One of the things I can think of:

  • move the files within the repository to a lib directory, where they don't get modified all the time
  • .gitignore the files in their definitive location, the one where they have to be but get unwanted changes all the time
  • add an "init" script to your repository that people need to run once after cloning and before starting work. This script copies the files into the right location.
like image 64
Barend Avatar answered Sep 21 '22 15:09

Barend