I'm working with small binary files in Mercurial as posted.
This binary files can be dumped as text to make a diff between versions, but the problem is that the files comes in pairs (eg: Form.scx / Form.sct), and I cannot found a way to tell Mercurial to "make a snapshot" (copy to a temporary location) of the other corresponding file when I do an hg ediff.
Just make a quick script and set that as the tool for extdiff. I'm guessing you're on Windows, but whatever the powershell equivalent to this is:
#!/bin/sh
binary-to-text $1 /tmp/$1.sct
binary-to-text $2 /tmp/$2.sct
diff /tmp/$1.sct /tmp/$2.sct
rm /tmp/$1.sct /tmp/$2.sct
That creates, compares, and then deletes the text versions. You'd want to be careful to not overwrite, deal with multiple concurrent invocations, etc.
Then configure a new command to run your script:
[extdiff]
cmd.mydiff = that_script_above.sh
Then you can do things like:
hg mydiff
Ideally you have only the "source" bonary format in your respository, not the text format, as you shouldn't keep generated items in the repo -- because if you update one but not the other you have an inconsistent state. Generating the comparable text files on demand is a better way to go.
As suggested by #Ryan, I ended up with a small batch previous to the diff program:
#echo off
set f1=%1
set f2=%2
::Temporary dir created by hg to copy the snapshot file
set tdir=%~dp1
::Original repository dir
set repo=%~dp2
::Filename extension
set ext=%~x1
::The binary files comes in pairs: scx/sct \ vcx/vct ...
set ex2=%ext:~0,-1%t
::Check if "dumpable" extension
echo %ext% | grep -iE "(vcx|vct|scx|sct|pjx|pjt|frx|frt)" > nul && goto DumpFile
goto diff
:DumpFile
set f1="%tdir%\_Dump1.prg"
set f2="%tdir%\_Dump2.prg"
::Get the pair file from the repository
hg cat %repo%\%~n1%ex2% -o "%~dpn1%ex2%" -R %repo%
::Do the dump, then the diff
MyDumpProgram.exe %1 %f1%
MyDumpProgram.exe %2 %f2%
goto diff
:diff
ExamDiff.exe %f1% %f2%
pause
and then config the batch in %UserProfile%\.hgrc
[extdiff]
cmd.ediff = d:\Utiles\diff2.bat
Related
I have a large amount of text files stored on a Red Hat server that contain explicit Windows paths. Today, that path has changed and I would like to change the text files to reflect the new path. As they are Windows paths, they all contain single backslashes. I would like to maintain the single backslashes if possible.
I wanted to ask what the best method to perform this string replacement would be. I have made backups of folders so that I may test on a smaller scale before applying to the larger scale that will affect my group members.
Example:
Change $oldPath to $newPath in all *.py files recursively contained in current directory.
i.e. $oldPath\common\file_referenced should become $newPath\common\file_referenced
Robustly using any awk in any shell on every Unix box and regardless of which characters your old or new directory paths contain and whether or not the final directory in either old or new could be a substring of another existing directory name:
$ cat file
\old\fashioned\common\file_referenced
$ oldPath='\old\fashioned'
$ newPath='\new\fangled\etc'
$ awk '
BEGIN { old=ARGV[1]; new=ARGV[2]; ARGV[1]=ARGV[2]="" }
index($0"\\",old"\\")==1 { $0=new substr($0,length(old)+1) }
1' "$oldPath" "$newPath" file
\new\fangled\etc\common\file_referenced
To update all .py files in a directory you could use GNU awk for -i inplace, or you could do for i in *.py; do awk '...' old new "$i" > tmp && mv tmp "$i"; done, or you could use find and/or xargs, etc. - any of the common Unix ways to process multiple files with any command.
how do I open from terminal window only files with conflicts during git/mercurial merge in textmate/sublime text2 editors
You can use the following to open all files with git merge conflicts in sublime text:
git diff --name-only | uniq | xargs subl
I wanted to add another answer. git diff --name-only will give you all files that have diffs. This is why sometimes it will yield duplicate entries because it marks the file as "modified" as well as in a merge conflict state. Piping it into uniq is a good solution for this but git diff --name-only will also include files you might have purposely changed so it doesn't actually filter only files with merge conflicts. When you are in the middle of rebasing, this is probably not going to happen often though I would say in most cases #StephanRodemeier's answer works.
However, what you can do though is leverage the --diff-filter option which assigns a states to files. See more in the docs
--diff-filter=[(A|C|D|M|R|T|U|X|B)…[*]]
Select only files that are Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R), have their type (i.e. regular file, symlink, submodule, …) changed (T), are Unmerged (U), are Unknown (X), or have had their pairing Broken (B). Any combination of the filter characters (including none) can be used. When * (All-or-none) is added to the combination, all paths are selected if there is any file that matches other criteria in the comparison; if there is no file that matches other criteria, nothing is selected.
It seems when files are in the both modified state, the diff status gets set to U (Unmerged) and M (Modified) so you can filter for only Unmerged files.
git diff --diff-filter=U --name-only | xargs subl
Should work without needing to pipe into uniq
Another thing you can consider is simply setting your editor as the difftool i.e. for VSCode documentation specifies how to do this by adding this to your .gitconfig
[diff]
tool = default-difftool
[difftool "default-difftool"]
cmd = code --wait --diff $LOCAL $REMOTE
By default all files changed in a changeset are on the same line, which makes them very easily to skip one or two, and hard to read.
How to make each file show on its own separate line?
The real way to see information about changed files is to use hg status. This shows the files that were modified in revision 100:
$ hg status -c 100
But if you want to have the log messages as well, then hg log is of course a natural starting point. Unfortunately there is no built-in switch that will make it display one file per line.
However, the output of hg log is controlled by a template system and you can write your own styles for it. The default style is here and you can customize to do what you want by changing
file = ' {file}'
to
file = '{file}\n'
Then save the new style as my-default.style and add
[ui]
style = ~/path/to/my-default.style
to your configuration file. This gives you one file per line and it even works when there are spaces in your file names.
I'm aware of one problem: you lose colors in the hg log output. It turns out that Mercurial is cheating here! It doesn't actually use the default template I showed you when generating log output. It doesn't use any template system at all, it just generates the output using direct code since this is faster. The problem is that the color extension only work with the hard-coded template. When you switch to a custom template and thereby invoke the template engine, you lose the color output.
However, you can recover the colors by inserting the ANSI escape codes directly into your template (on Unix-like systems). Changing
changeset = 'changeset: {rev}:{node|short}\n{branches}...
to
changeset = '\033[33mchangeset: {rev}:{node|short}\033[0m\n{branches}...
does the trick and hard-codes a yellow header line for the changeset. Adjust the changeset_verbose and changeset_quiet lines as well and you'll have colored output with your own template.
The hg template help file has this gem in its examples.
Format lists, e.g. files:
$ hg log -r 0 --template "files:\n{files % ' {file}\n'}"
This works on Windows without any translation.
I believe there is no built-in way to achieve this, but a bit of sed (also available for Windows: http://gnuwin32.sourceforge.net/packages/sed.htm) can help:
hg log --template "Rev: {rev}:{node}\nDate: {date|isodate}\nFiles: {files}\n\n" -l 10 | sed -e '/^Files:/s/ /\n /g'
Output:
Rev: 1:2538bd4661c755ccab9b68e1d5e91144f6f97d33
Date: 2011-12-20 15:47 +0100
Files:
test1.txt
Rev: 2:853a6f3c505308c9babff5a5a2f1e09303f1689c
Date: 2011-12-20 15:44 +0100
Files:
test2.txt
test3.txt
Explanation of sed -e '/^Files:/s/ /\n /g':
/^Files:/ searches for lines starting woth "Files:", and applies the following search and replace just to those line
s/ /\n /g replaces all lines with a newline, followed by the spaces.
This solution won't work when file names contain spaces.
To see all files that changed in a revision, use:
hg status --change REV
hg log --style changelog
OR
hg log --template "Description: {desc}\n" - supported keywords like desc, files etc. are listed here
I want to know how to create a PATCH for the difference file I got by comparing two binary files.
$cmp -l > output file name
I checked for text files 'diff" can be used to compare and generate a PATCH file
$ diff -u oldFile newFile > mods.diff # -u tells diff to output unified diff format
I want to apply the PATCH on the old binary image file to get my new binary image file.
Diff and Patch are designed to work with text files, not arbitrary binary data. You should use something like bsdiff instead.
If your repository, or package is using git you can make binary diff with
git diff --patch --binary old_dir patched_dir
Of course you can also use it with commits
git diff --patch --binary commit1 commit2
JDIFF is a program that outputs the differences between two (binary) files.
Also you can use therdiff command.
If you still want to use diff & patch. Here is a way...
Write a c program yourself to insert a newline character at the end of every 512/1024/your_choice bytes (this is just to fool the diff as it compares the files line by line). Run this script on your two input files.
Then run 'diff -au file1 file2 > mod.diff (you will get the patch here)'
Patching is simple 'patch < mod.diff'
Than again write a program to remove the newlines from the binary file. That is all...
So the utility Diff works just like I want for 2 files, but I have a project that requires comparisons with more than 2 files at a time, maybe up to 10 at a time. This requires having all those files side by side to each other as well. My research has not really turned up anything, vimdiff seems to be the best so far with the ability to compare 4 at a time.
My question: Is there any utility to compare more than 2 files at a time, or a way to hack diff/vimdiff so it can do multiple comparisons? The files I will be comparing are relatively short so it should not be too slow.
Displaying 10 files side-by-side and highlighting differences can be easily done with Diffuse. Simply specify all files on the command line like this:
diffuse 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt 10.txt
Vim can already do this:
vim -d file1 file2 file3
But you're normally limited to 4 files. You can change that by modifying a single line in Vim's source, however. The constant DB_COUNT defines the maximum number of diffed files, and it's defined towards the top of diff.c in versions 6.x and earlier, or about two thirds of the way down structs.h in versions 7.0 and up.
diff has built-in option --from-file and --to-file, which compares one operand to all others.
--from-file=FILE1
Compare FILE1 to all operands. FILE1 can be a directory.
--to-file=FILE2
Compare all operands to FILE2. FILE2 can be a directory.
Note: argument name --to-file is optional.
e.g.
# this will compare foo with bar, then foo with baz .html files
$ diff --from-file foo.html bar.html baz.html
# this will compare src/base-main.js with all .js files in git repo,
# that has 'main' in their filename or path
$ git ls-files :/*main*.js | xargs diff -u --from-file src/base-main.js
Checkout "Beyond Compare": http://www.scootersoftware.com/
It lets you compare entire directories of files, and it looks like it runs on Linux too.
if your running multiple diff's based off one file you could probably try writing a script that has a for loop to run through each directory and run the diff. Although it wouldn't be side by side you could at least compare them quickly. hope that helped.
Not answering the main question, but here's something similar to what Benjamin Neil has suggested but diffing all files:
Store the filenames in an array, then loop over the combinations of size two and diff (or do whatever you want).
files=($(ls -d /path/of/files/some-prefix.*)) # Array of files to compare
max=${#files[#]} # Take the length of that array
for ((idxA=0; idxA<max; idxA++)); do # iterate idxA from 0 to length
for ((idxB=idxA + 1; idxB<max; idxB++)); do # iterate idxB + 1 from idxA to length
echo "A: ${files[$idxA]}; B: ${files[$idxB]}" # Do whatever you're here for.
done
done
Derived from #charles-duffy's answer: https://stackoverflow.com/a/46719215/1160428
There is a simple an good way to do this = GREP.
Depending on the size of the text you can copy and paste it, or you can redirect the input of the file to the grep command. If you make a grep -vir /path to make a reverse search or a grep -ir /path. This is my way for certification exams.