Search code examples
c#vb.netgitgit-diffgit-for-windows

Git diff between 2 tags without full fetch fails running using git-bash.exe


I am trying to run git-cmd.exe from my code using Process. Below commands when passed to git-cmd.exe runs successfully when the git diff is happening between 2 branches.

git init
git remote add origin "<repo-name>"
git fetch origin <branch1>
git fetch origin <branch2>
git diff --name-only --diff-filter=d <branch1>:<folder1> <branch2>:<folder1>

I need to find the file names which were modified or added in <folder1> only, between the given branches. I am executing these commands by passing them as a string[] to a function.

Public Function RunAndReturnExitCode(ByVal Command As String(), ByVal Directory As String,
                                         Optional ByVal MaximumWaitTime As Integer = -1,
                                         Optional ByRef Output As String = Nothing,
                                         Optional ByRef Errors As String = Nothing) As String
        Dim exePath As String = "C:\Program Files (x86)\PortableGit\git-cmd.exe"
        Dim si As ProcessStartInfo = New ProcessStartInfo(exePath)
        si.RedirectStandardInput = True
        si.RedirectStandardOutput = True
        si.RedirectStandardError = True
        si.UseShellExecute = False
        si.WorkingDirectory = Directory

        Dim p As Process = Process.Start(si)

        With p.StandardInput
            .WriteLine("cd /d """ & Directory & """")
            Array.ForEach(Command, Sub(c) .WriteLine(c))
            .WriteLine("exit")
        End With
        p.WaitForExit(MaximumWaitTime)
        Output = p.StandardOutput.ReadToEnd()
        Errors = p.StandardError.ReadToEnd()
        Return p.ExitCode.ToString()
    End Function

Due to performance issues, we have now started working on tags. So, I am now doing:

git init
git remote add origin "<repo-name>"
git fetch origin refs/tags/[tag1]
git fetch origin refs/tags/[tag2]
git diff --name-only --diff-filter=d [tag1]:[folder1] [tag2]:[folder1]

Here, the diff command fails by:

fatal: Invalid object name '[tag1]'.

I tried running a few commands manually from git-cmd.exe, where I found git checkout refs/tags/[tag1] itself failed by:

error: pathspec '[tag1]' did not match any file(s) known to git.

Does this mean that my local repository does not have any info of [tag1]? If not, then why was there no error while fetching them? Can anyone suggest here, how I can fetch only these 2 tags and do a diff between them?
Tried git diff tag1 tag2, but its failing by :

fatal: ambiguous argument '[tag1]': unknown revision or path not in the working tree.

Please please let me know if any more inputs are required here from me. Also, I can not do a git fetch --tags as it hangs (I suppose, this is not the issue here as fetching the tags separately does not hang). To add, my organization does not permit usage of https://github.com/libgit2/libgit2sharp/.

EDIT:
As suggested by @torek, a git fetch refs/tags/tag1 was a wrong approach. I have now updated it to:

git fetch origin +refs/tags/tag1:refs/tags/tag1 +refs/tags/tag2:refs/tags/tag2

The command works fine on git-cmd.exe and I am able to get the diff. But it hangs when I fire through a process. My SSH repository does not have a pass-phrase, so it is for sure that the RSA Aunthentication isn't failing. Any suggestions here? Am I firing the commands correctly via the process?


Solution

  • This:

    git fetch origin refs/tags/[tag1]

    is wrong as it obtains the desired commit but does not write any name in your repository. The commit is now available through FETCH_HEAD, but only until the next git fetch. That is:

    git fetch origin refs/tags/[tag2]

    obtains that desired commit, but overwrites FETCH_HEAD, so that now the only name you have—FETCH_HEAD—refers only to the second desired commit.

    To fix this, you could either fetch both and discard their tag names, but now have both hash IDs in FETCH_HEAD (you would have to retrieve them yourself), or you can direct git fetch to create or update your refs/tags/tag1 and refs/tags/tag2 names:

    git fetch origin +refs/tags/tag1:refs/tags/tag1 +refs/tags/tag2:refs/tags/tag2
    

    The colon and second name provide the name of the reference to create-or-update in your Git repository. The leading plus sign + here tells git fetch that this particular update should be forced, i.e., it should overwrite any previous tag of the same name.

    Of course, git fetch --tags should work. (git pull --tags means run git fetch --tags, then run a second Git command, probably git merge. If you don't want to run any second Git command automatically, don't use git pull.) If this hangs, it may be worth investigating why: all it does is call up the other Git just like any git fetch, but this time also fetch refs/tags/*:refs/tags/*.