My .gitattributes has the following in order to diff the XCode project (which is plain text)
*.pbxproj -crlf -diff -merge
But when I diff, still showing binary file
# git diff MyApp.xcodeproj/project.pbxproj
diff --git a/MyApp.xcodeproj/project.pbxproj b/MyApp.xcodeproj/project.pbxproj
index xxx..xxx xxx
Binary files a/MyApp.xcodeproj/project.pbxproj and b/MyApp.xcodeproj/project.pbxproj differ
My .gitattributes is in the same level of .git folder
Correct. Your .gitattributes is saying to treat the file as binary when it comes to diffing and merging. Take a look at this StackOverflow question, which is awfully similar to yours: Git and pbxproj
Related
I have two (big) files and what I need is to extract changed/added lines only. Is a plain text file (CSV).
Simply return and save a third file with these lines..
UPDATE
I resolved with DiffMerge using the "Show Differences Only" function built in described here.
By the way, I still require a solution that "programmatically" do the same thing but I will create another Question maybe because I need it in a Linux environment.
UPDATE 2
Resolved also with TortoiseGit, see below.
Select two files, and TortoiseGit -> Diff
Create Patch file in TortoiseGitMerge
the unified diff file
UPDATE
For viewing diff only, using "Collapse".
UPDATE 2
If you don't need the context, just set the "Context lines for patches" to zero.
diff --changed-group-format='%<' --unchanged-group-format='' file1 file2
What you are looking for could be as simple as the default unified diff format given by git diff but with context lines stripped. You will still get the location information before every change.
git diff --unified=0 <commit1>:<path/to/file1> <commit2>:<path/to/file2> > <output file>
The files do not have to be versioned under Git, you can just omit the commit reference in that case (or when comparing separate files in same version). For different versions of the same file
git diff --unified=0 <commit1> <commit2> -- <file> > <output file>
I must have read at least 50 StackOverflow questions and answers that say that Git cannot track directories. And yet, that is exactly what seems to be happening.
I created a project (.NET, on Windows), and added and committed all the files prior to adding a .gitignore. Realizing my mistake later on, I git rm -r --cached :/ everything, added this .gitignore, and the re-added and committed my files. The thing is, git still tracks my obj and bin folders even though they seem to be ignored in the .gitignore.
Here are the relevant lines from the .gitignore:
[Bb]in/
[Oo]bj/
bin/**
obj/**
One or two of those might not make sense, I'm not totally familiar with .gitignore rules and was just trying to see what would stick.
Here's what I get for git status:
Untracked files:
(use "git add <file>..." to include in what will be committed)
src/main/dotnet/ETB/ETB.Droid/bin/
src/main/dotnet/ETB/ETB.Droid/obj/
src/main/dotnet/ETB/ETB.iOS/bin/
src/main/dotnet/ETB/ETB.iOS/obj/
src/main/dotnet/ETB/ETB/bin/
src/main/dotnet/ETB/ETB/obj/
src/main/dotnet/packages/
This is even after I do something like git rm -r --cached .\src\main\dotnet\ETB\ETB.Droid\bin from the root level. There are also ZERO tracked files from within these directories that appear in the "Changes not staged for commit" section when I do a git status.
I'm really, really stumped. Can anyone help me figure out why I can't ignore these directories completely?
Update
I made the changes that the commenters suggested, and it seemed to solve some, but not all, of my problems (sorry I had it marked answered for a bit there). Relevant lines in my .gitignore at the root level are:
**/[Dd]ebug/**
**/bin/**
**/obj/**
That first line is probably not necessary, but I figured it couldn't hurt. There is definitely no extra whitespace on any of these lines.
For some reason, only one of the obj directories is still showing up in Git. I even deleted and re-added everything just to try it out.
The offending directory is the ETB.Data directory:
Untracked files:
(use "git add <file>..." to include in what will be committed)
src/main/dotnet/ETB.Data/
So I ran this command:
git rm -r --cached .\src\main\dotnet\
I then committed those deletes. Then I tried to re-add the directory
git add .\src\main\dotnet
When I look at my status, here is what I'm seeing:
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: src/main/dotnet/ETB.Data/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs
new file: src/main/dotnet/ETB.Data/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs
new file: src/main/dotnet/ETB.Data/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs
new file: src/main/dotnet/ETB.sln
...
...
Why do these files keep showing up?! The obj and bin directories in other project directories are being ignored. Does anyone know why this one isn't being ignored?
You need to tell git to ignore all the bin/obj files/folders, not just the ones at its root :
**/bin/**
**/obj/**
From man gitignore :
A leading "**" followed by a slash means match in all directories. For example, "**/foo" matches file or directory "foo"
anywhere, the same as pattern "foo". "**/foo/bar" matches file or directory "bar" anywhere that is directly under
directory "foo".
A trailing "/**" matches everything inside. For example, "abc/**" matches all files inside directory "abc", relative to
the location of the .gitignore file, with infinite depth.
Thats very simple because your line in your .gitignore file are not correct. I can't test it now but try something like this for example
**/bin/**
**/obj/**
When you don't write the * at the beginning your line is interpreted as the start.
There is a good comment if you read the man page.
. A leading "" followed by a slash means match in all directories.
For example, "/foo" matches file or directory "foo" anywhere, the
same as pattern "foo". "**/foo/bar" matches file or directory "bar"
anywhere that is directly under directory "foo".
. A trailing "/" matches everything inside. For example, "abc/"
matches all files inside directory "abc", relative to the location of
the .gitignore file, with infinite depth.
I am creating a svn diff patch, however it seems the image files are not getting included. The patch contain similar lines for each image file, as shown below:
Index: crimgeoprofile/code/jquery/css/ui-lightness/images/animated-overlay.gif
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: crimgeoprofile/code/jquery/css/ui-lightness/images/animated-overlay.gif
===================================================================
--- crimgeoprofile/code/jquery/css/ui-lightness/images/animated-overlay.gif (revision 1510040)
+++ crimgeoprofile/code/jquery/css/ui-lightness/images/animated-overlay.gif (working copy)
I am using the following command to create a patch:
svn diff > test.diff
Any suggestions on how I can include image files will be appreciated.
SVN does not support to include binary files in diffs. As a side note: git does support binary files. The resulting patch file looks like this:
diff --git a/bin/windows/SDL_mixer.dll b/bin/windows/SDL_mixer.dll
new file mode 100644
index 0000000000000000000000000000000000000000..f48ee2da696f92b66940b91b52aa53c2
GIT binary patch
literal 160256
zcmd?S4SZD9)i*kmOyYopCrYBxf<%o9l`2uFL_&=TgA|RT7>j7Ev^CX7sg%wregu+E
z26K8G$kPW}+uD|hZFwrKv_*(YAs#UMf~XNJW(<Ug6wVlm;iDl0WbXgJ_BoSD06*UQ
z-h1DBFF(yWXYaMwUVE*z*Is+=k13j2?MQYw94`DHi#Z&%c=BJq{Qc}d<;Xr~#Ovoc
zRu6jXl3M4jZ(VZNLl6HbYtG!qzCU-??5yw3`oRw#^JRVK!K}IdA7nlJgRDunPtThD
So technically it is possible, it just doesn't work with svn. So if you desperately need a patch file including binaries, consider checking out svn using git. It's easy: git svn clone http://path/to/svn. Also works similar with svn://.... You can then create a git diff, and apply that diff to any target. The target does not need to be a git repository. git apply my.patch
With Suversion 1.9 you can use --git flag for include binary content to patch file, for example:
svn diff https://storage/svn/project/trunk --git -c 42 > patch-42.diff
Subversion 1.8 already have --git flag, but ignore binary content with it.
Unfortunately, svn diff does not handle binary data.
Check some of the answers from: subversion diff including new files
In particular: https://stackoverflow.com/a/2255846/9822
The Image files are getting included in your diff as indicated by the lines with --- and +++ but they are included as whole files in the patch - this is due in part the the problem of how to meaningfully display changes in binary data such as images in a text only format - unless you would like pages of hex differences, (such as fc -b a.gif b.gif would produce).
So you are told that the files have changed and it is up to you to decide how you would like to compare them - for image files one of the best comparisons of the significant differences is the human eye - you would not expect a revision control system to be able to tell you "This was a picture of a bald man frowning but now it is a pretty redhead cheerleader smiling" would you?
The command :Gdiff is equivalent to running git diff on that file.
What's the equivalent for git diff --staged or git diff --cached?
I've found a way to do this. Run :Git, you should get a window with contents like the following:
# Head: master
# Merge: origin/master
# Help: g?
#
# Staged (1)
# M example.txt
#
Scroll down to the staged file, example.txt, and press dd. This will open a diff view, comparing what's in HEAD and what's in the index. You'll notice on the bar on the bottom that both the filenames are special Fugitive filenames.
Also while in :Git preview window, you can press g?, which will list all the mappings valid in the current context.
While vim-fugitive does not supply direct analogues for git diff --staged or git diff --cached, it does supply a general-purpose Vim command for piping the output of arbitrary git commands into read-only Vim buffers: :Git!.
Inapplicable Answers
Before we get to that, let's explicitly restate the question. git diff --staged and git diff --cached are synonyms for the same underlying operation: diffing the contents of the index (the set of all staged changes) against the contents of the HEAD (the most recent commit for the current branch), typically for reviewing changes prior to commit. The stated question then becomes:
What is the most effective means of reviewing all staged changes in vim-fugitive?
It should be clear that the currently accepted self-answer fails to address this question. The next highest rated self-answer is no better.
:Gstatus bindings only apply to the file on the current line and hence cannot by definition be used to review all staged changes. Moreover, the :Gstatus D binding doesn't even review all staged changes for the file on the current line. It only diffs the index and working tree copies of that file, rather than diffing the index and most recently committed copies of that file (which is an altogether different beast).
:Gdiff HEAD is similarly inapplicable. It only diffs the most recently committed and working tree copies of the file corresponding to the current buffer. :Gdiff without an argument is equivalent to the :Gstatus D binding, again diffing the index and working tree copies of that file. Neither reviews all staged changes.
Applicable Answers
emaniacs struck the closest to a working solution with this comment to the latter answer:
:Git diff --staged
Now we're approximating the truth!
:Git pipes the output of the passed git command to the current external pager, permitting a liesurely review of all staged changes external to Vim. But there's the rub: external to Vim. That means no Vim bindings, buffers, or syntax highlighting. Ideally, we'd prefer a read-only Vim buffer syntax highlighting the output of git diff --staged. Can we do this?
The Solution
We can, or Tim Pope isn't the Vim Pope. The !-suffixed variant of :Git does just that, permitting a liesurely review of all staged changes within Vim complete with Vim-based syntax highlighting of change differences:
:Git! diff --staged
Yeah. It's pretty awesomeness.
But let's go a step farther. In the time-honoured tradition of slothful slackers everywhere, let's define a new Vim command :Greview encapsulating this operation and a new binding <leader>gr running this command. Just stash the following into your .vimrc:
command Greview :Git! diff --staged
nnoremap <leader>gr :Greview<cr>
Assuming <leader> to be ,, reviewing all staged changes reduces to ,gr. It couldn't get any Vimmier.
:Gdiff HEAD
Gdiff takes an revision argument. So you can pass it HEAD. This is not equivalent to git diff --staged, but it can serve a similar purpose.
Update: 3/28/2017,
Current version of fugitive will do this automatically when you press D on a file.
if the file is staged, only staged changes will be showed in the diff.
If the file is not staged, then only change that are not staged will be visible.
As already noted, Gdiff, Gdiff : or Gdiff :0 gives you the diff with the index,
Gdiff - or Gdiff HEAD gives the diff with the HEAD.
Triple-split approach
So doing a diff first with : then with - show 3 diff-panes in vim:
HEAD
index ("cached" or "staged")
working tree
command! -bar Gvstage :Gvdiff -|Gvdiff : " vertical 3-split
command! -bar Gsstage :Gsdiff -|Gsdiff : " horizontal 3-split
Of course you can also just to Gvdiff - if you're already in diff mode.
Now pushing and getting changes is sligthly more complicated with 3 open windows, however, you can diffput from index to working tree and vice-versa easily, as on the HEAD modifiable is off, so it can never be targeted.
Otherwise, you can add some shortcuts for the diffput and diffget commands, knowing that they can take a "buffer specifier", which can be a pattern (see :help merge) or the buffer number. I modified the previous commands to save the initial buffer's number and use patterns for the others:
command! -bar Gvstage :let t:working_copy=bufnr('%')|Gvdiff -|Gvdiff : " vertical 3-split
command! -bar Gsstage :let t:working_copy=bufnr('%')|Gsdiff -|Gsdiff : " horizontal 3-split
nnoremap <Leader>hg :diffget fugitive://*/.git//[0-9a-f][0-9a-f]*/<CR> " HEAD get
nnoremap <Leader>ig :diffget fugitive://*/.git//0/<CR> " index get
nnoremap <Leader>ip :diffput fugitive://*/.git//0/<CR> " index put
nnoremap <Leader>wg :diffget <C-R>=t:working_copy<CR><CR> " work get
nnoremap <Leader>wp :diffput <C-R>=t:working_copy<CR><CR> " work put
Difftool approach
Alternately, if you just want a nice vimdiff view of what is staged instead of a patch, let me sugget:
command! Greview :exec "Git difftool --tool=vimdiff --staged " . fugitive#buffer().path()
This starts a new instance of vim, so when you quit it you go back to your tabs and windows you already had opened, which is perfect. This if faster (at least for me) than transitioning through the git status window, but has the drawback that you can't edit the staged file.
Use :Gtabedit #:% | Gdiff :.
This is better than the other answers because it opens in split view just like :Gdiff, rather than dumping diff syntax into a single buffer. When you're done, just :tabc to get back.
Explanation
Gtabedit open a new tab and edit a fugitive object:
from commit # (HEAD), a specific file :, the current file %.
Gdiff diff the current buffer against another fugitive object:
from the index : (you can specify the file again with :% but it's not needed).
Bonus
We now have fugitive equivalents for git diff (:Gdiff) and git diff --staged (the command above). To get the behaviour of git show on the current file, use :Gtabedit #~:% | Gdiff #.
References
https://github.com/tpope/vim-fugitive/issues/837#issuecomment-247985612
:help fugitive-object
In case you somebody stumbled on this question.
:Gdiff --staged
will do.. :)
I create .gitignore in folder with my repository near .git
project
--.git
--.gitignore
--Source
----tmp
----scr
But git doesnt see it, wouldnt ignore files in .gitignore
My .gitignore file:
*.tmp
*~
*.pdb
*.user
*.suo
Sources/tmp
What`s wrong?
Up:
I created new repositiry, add .gitignore before init commit - it work!
But if I add in old repository it doesn`t...
The problem is that you're specifying glob syntax when the default syntax for git is regex.
Try this instead:
.*\.tmp
.*~
.*\.pdb
.*\.user
.*\.suo
Sources\/tmp
What you have should work, though your directory listing has Source/ while your .gitignore has Sources/.
The one thing that springs to mind is that the line endings might not be what git is expecting.
Also, as tmp is a directory, usually a trailing '/' is used:
Source/tmp/
Finally, you can also create a .gitignore in Source/ with the line:
tmp/
instead of having it in the top directory.