Can Git automatically handle inserts when merging is resolved?

When resolving merge conflicts, most of the time this is due to the fact that two people are inserted at the same point in the file. And I always do the same: use the new code on the left side, copy the new code on the right side and add it after the code on the left side.

I wondered if I would always do the same, it should be possible to automate this. Can I tell Git to make sure that both new snippets can be used one after the other?

I think that if the inserts are a few lines apart (the Git situation resolves automatically), it is unlikely that an error will occur. I will check the result anyway.

(I am currently using DiffMerge as my mergetool, if that matters.)

+6
source share
1 answer

To do this, you need to declare a merge driver :

This is the designated in .gitattributes , executed in the destination branch (the one where you do the merge)

 echo yourFiles merge=addTheirs>.gitattributes git add .gitattributes git commit -m "record addTheirs merge driver" 

(replace yourFiles with the file template you want to see in order to apply merge permission)

But it also needs to be configured locally:

 git config merge.addTheirs.name "keep additions only" git config merge.addTheirs.driver addTheirs.sh 

The trick is in addTheirs scripts called with %O , %A , %B (ancestor, ours, their)

A diff -u %A %B will provide you with hunks diff, for example:

 @@ -1,11 +1,11 @@ line 1 line 2 -line 3 from master +line 3 from dev line 4 line 5 line 6 line 7 line 8 +line 8bis from dev line 9 line 10 -line 11 

Despite the lack of a diff header, patch will still be able to add new lines and delete the old one (and that you want to keep ours and add them).
On Windows, you can take gnu patch , but you need to add a manifest .

 patch -u -p0 $3 $2 

You can try to filter out the removal from the patch before applying it.

 patch=$(diff -u $2 $3 | grep -v "^-") 

But the hunk header ( @@ -1,11 +1,11 @@ ) will no longer match the expected number of lines (if you add only two lines and delete 0, it should end with +1,13 , nit +1,11 )

You need to process your patch to:

  • filter deletion
  • customize header headers

This means that addTheirs.sh (for placement anywhere on your path, even on Windows) can be:

 #!/bin/bash patch=$(diff -u $2 $3) echo "${patch}" > f.pp patch2=$(./padd f.pp) echo "$patch2" > fp patch -u -p0 $2 -i fp 

( diff is part of the 200+ unix command of the git-for-windows package command, so it all works on Windows or Unix)

The 'padd' utility (patch add) is a script to remove any delete line from each line and update the hunk header to track the actual line number.

I did mine in Go ( https://golang.org/ , just unzip the go distribution anywhere and add it to your PATH )

Copy the following into the padd.go file and enter go build padd.go : you will get a padd that can call the merge driver to configure the patch.

 package main import ( "fmt" "io/ioutil" "os" "regexp" "strconv" "strings" ) // @@ 1,11 1,13 @@ <= extract prefix '@@ 1, 11 1,' and counter '13' var chunkre = regexp.MustCompile(`(?m)^(@@.*,)(\d+)\ s+@ @.*$`) var patch = "" func main() { fname := os.Args[1] f := "" if b, err := ioutil.ReadFile(fname); err != nil { panic(err) } else { f = string(b) } lines := strings.Split(f, "\n") prefix := "" counter := 0 var err error hunk := "" for _, line := range lines { snbadd := chunkre.FindAllStringSubmatch(line, -1) if len(snbadd) > 0 { updatePatch(hunk, prefix, counter) hunk = "" prefix = snbadd[0][1] if counter, err = strconv.Atoi(snbadd[0][2]); err != nil { panic(err) } } else if prefix != "" { if strings.HasPrefix(line, "-") { counter = counter + 1 line = " " + line[1:] } hunk = hunk + line + "\n" } } updatePatch(hunk, prefix, counter) fmt.Println(patch) } func updatePatch(hunk, prefix string, counter int) { if hunk != "" { header := prefix + fmt.Sprintf("%d @@\n", counter) patch = patch + header + hunk } } 
+9
source

Source: https://habr.com/ru/post/989638/


All Articles