Cherry-pick with ignore whitespace / line-endings - linux

is there a way to tell git cherry-pick to use the renormalize merge strategy? I'm not sure the -X option is working.
I have a bunch of commits that seem to assume one type of line ending, and I'm trying to apply them to a branch that assumes another. Not having a good time...

So, for completeness, the answer is that the ignore-all-space merge strategy does the job:
git cherry-pick -X ignore-all-space <commit-id>
And that will let you painlessly cherry-pick commits made when the file had, eg, windows line endings onto a version that has unix file endings.

I know this question is significantly old, but adding this answer because this is the first post from googling "git cherry-pick ignore whitespace".
Even though -X ignore-all-space works fine, you have to manually check the commit if the cherry-pick without ignore space option had some conflicts. (or use --no-commit while cherry-picking and git diff --staged to review it)
In some cases, -X ignore-all-space option looks fine, but some indentations are wrong.
For example, suppose you had some merge conflict with leading whitespace while not using ignore-all-space, like this:
Change from theirs, Indent level 1(no conflict with/out whitespace)
<<<<< HEAD
Indent level 0
=====
Indent level 1 without any code change
>>>>> cherry-picked commit
In this case, -X ignore-all-space shows no conflict but the actual commit will look like this:
Change from theirs, indent level 1
Indent level 0
What happened here is they changed logic so the previous code (Indent level 0) should be indented to level 1, but it didn't because you specified ignore-all-space option.
So the tl;dr is:
-X ignore-all-space option also ignores leading whitespaces, which might be troublesome in some situations and languages like Python.
So you have to manually review after using that option, or...
Use -X ignore-space-at-eol instead, and handle leading whitespace conflicts manually.
But don't stop reading, because these options are not the main reason of this problems - the core of this problem is not everyone is sticking to same whitespace rules.
For leading&trailing whitespaces: use linting tools, or IDEs, or whatever to stick to same rules. This is not OS-specific and can be followed if your team puts some effort to making other developers' life easier.
For eol changes: this is OS-specific, but git fortunately supports core.autocrlf and core.eol for multi-platform development enveronment. see git-scm for more details.

Related

When using Git, when would I use one hyphen (-) over two hyphens (--)?

In Git, when I am performing a commit with add, I can use
git commit -am "My commit"
When I see examples of git log or in most other cases we use
git log --online
But I do not understand when I'd use one hyphen (-) or two hyphens (--). Can anyone please explain?
There is no big difference between - and --. It is just a convention in unix to use:
- when the option is one letter. In this case you can combine then: -am is equivalent to -a -m
-- when the option is a word.
-- without a word is used to separate options from arguments, that way you can use arguments starting with hyphen without having them interpreted as an option
Some options have the two forms (one letter or one word), some have only one of the two forms. Check the help of each command to find it.
git commit -am "My commit"
# is equivalent to
git commit --all --message "My commit"
Also you can read this question on Super User to learn more about this, as suggested by melpomene.
I've "OBSERVED" that single hyphen is used for single character options and double hyphens are used for multiple character option in git (and several other tools).
This is an indication to the program that whatever it sees after -- should be treated a single option. For example, --online specifies that "online" is an option. But if we use -online, we specify o,n,I,i,n,e are options.
However, this also depends on the tools we use. Most tools follow this pattern, which I think makes the parsing easier. But I've seen few program that can can take in multiple character option with a single hyphen. For example, "java -version" works just fine.
It largely depends on the command you're executing. Let's take git-add as an example.
The possible parameters to it are as follows:
git add [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
[--edit | -e] [--[no-]all | --[no-]ignore-removal | [--update | -u]]
[--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing]
[--chmod=(+|-)x] [--] [<pathspec>…​]
I picked this one in particular because there's a nice mix of short and long-form flags, as well as the double-hyphen in a peculiar place, which I'll get to in a moment.
First and foremost, the key difference between a single hyphen and a double-hyphened flag largely depend on what the command supports. You'll notice in git-add, there are some flags which use double-hyphens as a longer-form command, and the single-hyphen flags as a shorter way to express the same command. In that vein, --verbose and -v accomplish the same thing with different syntaxes.
That's established by convention, and is there for convenience's sake.
Now, to the point of the double-hyphen. In Unix-based systems, a double-hyphen following the flags represents the end of the command, which allows you to specify paths which would conflict with any of the flags present or above. As an example, if you have (for whatever reason) a file named -n, you can add it to Git by:
git add -- -n
So, to summarize:
Use a single hyphen for shorthand flags if it's supported.
Use a double-hyphen for long-hand flags if you remember the command name, or if there's no alternative (like in --ignore-missing).
Use a double-hyphen to signify the end of a command.
Using one hyphen - is to use shortcut parameters (one letter for each parameter) for parameters the most commonly used.
That's a Unix convention.
They are intended to be used only by the user in the command line because they are convenient.
Everywhere else (especially in scripts) , prefer the equivalent with 2 hyphens --, which is a good practice, to make it more meaningful for the future one (perhaps you) that will have to read it.
You could see parameters that have a one letter shortcut using the parameter --help on every Unix command.

Give vimdiff some hints

I've got two c++ files that I want to diff with vimdiff. One of them has a lot more function definitions at the start, before both have a common function that I'm actually interested in. However, vimdiff seems incapable to ignore all the function defs before the common one (perhaps because of different arguments).
Is there any way I can give a hint to vimdiff that, say, line xxx in file1.cxx is equals to line yyy in file2.cxx?
I'm open for alternative solutions without vimdiff, but they must be on linux and very preferably command line, since I'm ssh-ing and any graphical interface is a bit uncomfortable.
Vim just delegates the actual work of comparing the files to the external diff utility, cp. :help diff-diffexpr. The help page also shows how a different utility can be used. Unfortunately, I'm not aware of any more "intelligent" or configurable diff tool that would help in your situation.
A workaround might be (temporarily) removing the excess functions that you're not interested in, anyway. With the BlockDiff plugin, you don't actually need to modify the files. Just select the interesting lines in both windows and execute :[range]BlockDiff on them. Only those sections will then be diffed in a separate tab page. (The plugin mentions this requires a GUI, but Vim in a terminal supports tab pages just as well.)

Is there a way to adjust vimdiff's line position for a change?

I have fixed some indentation issues in my project and I'm looking at the vimdiff output for the before and after. I notice that vimdiff seems to be very confused as to what the actual changes are, rendering a pretty much useless output in this case:
For example, it seems to think that the very first line is a newly added line:
<div class="text-xs-center p-4">
In reality, all that has changed is the indentation. Vimdiff is not recognizing the changes properly.
In another, similar file, the diff works much better:
I think the difference is that in the second file I did not remove the first line break.
Is there a way to manually fix this sort of thing, so that the diff shows properly? I don't want to change either file, the changes are correct. But I'd like to tell vimdiff that it's comparing the wrong lines to one another.
Is this possible?
The underlying diff tool compares individual lines, regardless of whether "only" indentation changed, or something more fundamental. As in your first case, there's one extra unindented line, so diff recognizes that as unchanged, and this messes up the entire diff.
If you want to ensure that only indentation got changed, you can ignore whitespace changes via
:set diffopt+=iwhite
Then, the diff should show no changes at all (or, in your first example, only the added line 5).
Maybe there are also other diff utilities that more intelligently handle these cases. If you find such tool, you can configure Vim to use it via 'diffexpr'.

How do I accept both changes in vimdiff hunk?

When resolving merge conflicts, a fairly common pattern is that both I and another person have modified a list or some other section of code which commonly gets appended to. Such as:
global.registerFeature(fc);
global.registerFeature(fb);
global.registerFeature(fa);
<<<<<<<
global.registerFeature(aNewFeature);
=======
global.registerFeature(anotherNewFeature);
>>>>>>>
When I look at a merge conflict like this in vimdiff, vim gives me options for choosing one or the other. But what I want to do is apply both diffs. I usually just resort to editing the merged file directly (just deleting the merge markers); but is there an easier way to do this in vimdiff?
To combine changes from both the target and merge branches in a single command:
You can just delete the lines with Git conflict markers. The following two methods will delete all lines that start with:
<<<<<<<
=======
>>>>>>>
Method 1: Manually Entering and Executing a Command
:g/^<\{7}\|^|\{7}\|^=\{7}\|^>\{7}/d
Method 2: Implementing a User Defined Command
"Delete all Git conflict markers
"Creates the command :GremoveConflictMarkers
function! RemoveConflictMarkers() range
echom a:firstline.'-'.a:lastline
execute a:firstline.','.a:lastline . ' g/^<\{7}\|^|\{7}\|^=\{7}\|^>\{7}/d'
endfunction
"-range=% default is whole file
command! -range=% GremoveConflictMarkers <line1>,<line2>call RemoveConflictMarkers()
Vim diffget and diffput will only choose one branch or the other. So the only real solution other than the one given above is to manually yank and paste from both files into the working copy.
I'm not sure exactly what version control system you are using, but here is a guide for using Vim to do merges with Mercurial: https://www.mercurial-scm.org/wiki/MergingWithVim
You should be able to do something similar with whatever you are using, although keep in mind that vimdiff is not really meant for complicated merges, so it will be a bit kludgy. That same page links to the splice plugin, which is supposed to help with doing complex merges.

how did git handle one of several patches?

Let's say we have 5 patches for a file, and 4 of the patches changed the file content and add new lines. But we can still apply a single patch 5 to the git tree. Why? Since I thought the line numbers has changed, and so the line contents didn't match any more. How does git determine which line I made a change? Through the three line context of the change? I don't think it is plausible.
BTW, how to generate a number zero patch like [PATCH 0/5]? It seems format patch can only generate from 0001.
Through the three line context of the change?
This is how git apply describes it:
Ensure at least <n> lines of surrounding context match before and after each change.
When fewer lines of surrounding context exist they all must match.
So yes, even if the line numbers changed, the context is still key in determining if a patch should apply or not.
Regarding the numbering aspect, I didn't test, but see if the --start-number option of git format-patch command can help:
--start-number <n>
Start numbering the patches at <n> instead of 1.

Resources