1

I have a setup (it needs to be this way), where I am syncing updated files to a git repository. This happens when files changes, and the .git folder is ignored in this sync process.

so

  • client (with repo checkout) > file sync (ignoring .git) > server (with repo checkout)
  • client > upstream git repo (from time to time)
  • upstream git repo > server (from time to time)

Some times, I need to update git on server based on upstream, so I am using git fetch --all && git reset --hard origin/branchname. Which work for this purpose.

However, I want to be able to detect, if this actually updated any files or not. In other words, if the client file sync is up to date with the upstream git repo, I want to detect it..

The closest way to do this as I could find is an answer here which are using something like git merge-tree $(git merge-base FETCH_HEAD master) FETCH_HEAD master. The problem with that is that it shows changes, even if the file and content already exist...

updated with testcase

$ { ~/repos }$ mkdir a && cd a

$ { ~/repos/a }$ git init
Initialized empty Git repository in ~/repos/a/.git/

$ { ~/repos/a }$ echo file1 > f1 && git add f1 && git commit -m "1"
[master (root-commit) 9b1b025] ..
 1 file changed, 1 insertion(+)
 create mode 100644 f1

$ { ~/repos }$ git clone a b
Cloning into 'b'...
done.

$ { ~/repos }$ cd b

$ { ~/repos/b }$ ls
f1

$ { ~/repos/a }$ echo file2 > f2 && git add f2 && git commit -m "2"
[master 4e40da5] 2
 1 file changed, 1 insertion(+)
 create mode 100644 f2

$ { ~/repos/b }$ git fetch --all
Fetching origin
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ~/repos/a
   9b1b025..4e40da5  master     -> origin/master

# The folder `b` started with 1 file `f1`, and it can now
# see the new file `f2` as expected.
$ { ~/repos/b }$ git diff HEAD..origin/master
diff --git a/f2 b/f2
new file mode 100644
index 0000000..6c493ff
--- /dev/null
+++ b/f2
@@ -0,0 +1 @@
+file2

# Without using git (another file sync job, think rsync),
# the `f2` is created identical, but without informing git.
# After this, the repos contains the exact same data,
# but git doesn't know that.
$ { ~/repos/b }$ echo file2 > f2

# However, git diff still thinks this file is new..
# At this point, I want to be able to see if
# the origin/master is identical to the content of this repository.
$ { ~/repos/b }$ git diff HEAD..origin/master
diff --git a/f2 b/f2
new file mode 100644
index 0000000..6c493ff
--- /dev/null
+++ b/f2
@@ -0,0 +1 @@
+file2

# Untill I do a reset --hard
$ { ~/repos/b }$ git reset --hard origin/master
HEAD is now at 4e40da5 2

# Doesn't show any output
$ { ~/repos/b }$ git diff HEAD..origin/master
xeor
  • 5,301
  • 5
  • 36
  • 59
  • 1
    So... you want to know if `origin/branchname` is different from `branchname`? Isn't that just `git diff branchname origin/branchname`? Am I missing something about this question...? – Mark Adelsberger Jul 14 '17 at 13:28
  • Note that `git reset --hard` resets (to whatever comes out of the chosen commit) the files stored in the index and work-tree, so if you have files there that differ from those in any commit, those too will get changed. – torek Jul 14 '17 at 14:54

2 Answers2

1

You can see the diff between origin/master and HEAD before reset.

$ git fetch --all
$ git diff HEAD..origin/master        # see what is in origin/master that is not in HEAD (local latest commit)

$ git diff origin/master..HEAD        # see what is in HEAD that is not in origin/master

# If local uncommitted changes exist (tracked by git)
$ git diff origin/master

# for untracked/new files, one way is to use '-N' flag with 'git add' command
$ git add -N .
$ git diff origin/master

More about '-N': $ git add --help

  -N, --intent-to-add
       Record only the fact that the path will be added later. An entry for the path
       is placed in the index with no content. This is useful for, among other
       things, showing the unstaged content of such files with git diff and
       committing them with git commit -a.
Sajib Khan
  • 22,878
  • 9
  • 63
  • 73
  • Thanks.. That kinda made sense, but it didn't do the trick. I updated the question with an example of the problem. – xeor Jul 14 '17 at 20:08
  • Try `git diff origin/master` since you've uncommitted change (created `f2` file in repo `b` and not committed yet). `HEAD` points to the latest local commit. – Sajib Khan Jul 14 '17 at 20:30
  • Using `git diff origin/master` works on files already added and tracked by git. Did not work on new files however. This is much better than nothing.. So problem is halfway solved :) Can you think of a way doing it on new files? – xeor Jul 14 '17 at 20:45
  • You can use `git add -N`. I don't have any better solution for untracked files. – Sajib Khan Jul 14 '17 at 23:39
0

Just have the server do a checkout (by SHA) in post-receive and do your step 1 with git push. "File sync (ignoring .git)" while only doing it when something changed is exactly what pushing committed changes does.

jthill
  • 55,082
  • 5
  • 77
  • 137