Reputation: 19690
So I have master
which is the baseline, and I have an arbitrary situation on the developer's machine including:
Is there a way to see a diff of all of above against the remote?
Upvotes: 2
Views: 1754
Reputation: 19690
his is the solution i discovered
git add --all -N :/
git --no-pager diff origin/master
Upvotes: 2
Reputation: 488463
Not as a single command, but as long as you have access to the developer's machine and it has access to the other repository, yes. Let's just call the developer's machine M, and assume that on M, accessing the "main" repository is done through origin
, i.e., the developer ran git clone <url>
originally to create the repository that is now on M.
The first step is to make sure that the repository on M is up to date with the repository on the other system(s). Assume M$
is the prompt on machine M when in the clone:
M$ git fetch origin
The repository on M now has:
origin
.Now M has everything needed to generate any diff you like, and the question becomes: How would you like these diffs generated and presented?
Let's assume further that we are interested in:
Any commits on local branch B
that are not on origin/B
:
...--o--o--*--G--H <-- B
\
J--K--L <-- origin/B
Here there are two such commits, with hashes G
and H
.
You can git show
each such commit, to get a log message and a patch. Or, you can run git format-patch <options> origin/B..B
, to produce either individual patch files (the default) or a stdout stream (--stdout
) containing each commit as a patch. Note that format-patch
will not show merge commits and diffs of merge commits are tricky to get right, so we'll just ignore them.
If the repository is currently on branch B
(so that B
is HEAD
), you can just run git format-patch <options> origin/B
: the default for format-patch
is to treat a single argument as meaning <argument>..HEAD
. Hence:
M$ git format-patch --stdout origin/B > /tmp/commits
The difference between the tip of branch B
(commit H
) and what's in the index/staging-area. Let's assume, again, that HEAD
names branch B
, to make this easier:
git diff --cached > /tmp/tip-to-staged
This writes the diff to the standard output.
The difference between what's in the index and what's in the work-tree:
git diff > /tmp/staged-to-work-tree
This writes the diff to the standard output.
The difference between "nothing" (an empty tree) and each untracked file. This is the most difficult to get from Git, and also in a sense the silliest, since the difference between "nothing" and "some set of files" is just "some set of files". There is no single Git command to generate this, but you could just use git ls-files --other
to get the list of such files and then wrap them up however you like. Alternatively, you could write them into a commit; see below.
Files that are not only untracked, but also ignored. (Note that listing a tracked file as ignored has no effect on the tracked file: such a file is tracked and not ignored. "Ignored" is a status that applies only to a file that is also, already, untracked. In any case "untracked" merely means "not in the index".) This is the same as the untracked files in the previous point: we merely divide them into "untracked and ignored" vs "untracked and not-ignored". In fact, if you choose to use git ls-files --other
, you get all untracked files, including ignored ones, unless you add the --exclude-standard
option.
git stash save
to get untracked or all filesNote that we have had to use at least three Git commands:
git format-patch
git diff --cached
git diff
and we still do not have the untracked and/or ignored files. If we use git stash save
, we can get the last. We could even drop one (but only one) git diff
while adding at least one more git diff
. However, other things become more complex. In particular, git stash save
does nothing if there is nothing to stash, and we must check for this:
M$ old_stash=$(git rev-parse -q --verify refs/stash)
M$ git stash save --untracked # assuming you do not want ignored files
M$ new_stash=$(git rev-parse -q --verify refs/stash)
M$ [ "$new_stash" != "$old_stash" ] && have_stash=true || have_stash=false
If you want all files (untracked+ignored), use --all
instead of --untracked
.
We also need the hash ID of the empty tree:
M$ empty_tree=$(git hash-object -t tree /dev/null)
We can now get the diff from the empty tree to the commit containing the untracked-minus-ignored (--untracked
) or untracked-including-ignored (--all
) files:
M$ ($have_stash && git diff $empty_tree ${new_stash}^3) > /tmp/extra
M$ $have_stash && git stash pop
It's now safe to generate the other diffs, or you can do them before the stash save and maybe-pop. (And if you turn the above into a script there are somewhat less clumsy ways to write it.)
If you're not interested in preserving individual commits, you can just run a single git diff
from either commit *
or commit L
in the original diagram above. (If there are no new commits on origin/branch
these are the same commit.) This won't show what's in the index (staged) or work-tree (unstaged), of course. As before, you can play a few tricks with git stash save
to make commits from the index and work-tree and (optionally) --untracked
or --all
files. Since the work-tree commit from this action is, internally, a merge commit, you must manually diff it against the interesting parent. As before, untracked files should be diff-ed against an empty tree.
Upvotes: 1