diff --git a/config/branch.go b/config/branch.go index fe86cf542..652270a28 100644 --- a/config/branch.go +++ b/config/branch.go @@ -2,6 +2,7 @@ package config import ( "errors" + "strings" "github.com/go-git/go-git/v5/plumbing" format "github.com/go-git/go-git/v5/plumbing/format/config" @@ -26,6 +27,12 @@ type Branch struct { // "true" and "interactive". "false" is undocumented and // typically represented by the non-existence of this field Rebase string + // Description explains what the branch is for. + // Multi-line explanations may be used. + // + // Original git command to edit: + // git branch --edit-description + Description string raw *format.Subsection } @@ -75,9 +82,27 @@ func (b *Branch) marshal() *format.Subsection { b.raw.SetOption(rebaseKey, b.Rebase) } + if b.Description == "" { + b.raw.RemoveOption(descriptionKey) + } else { + desc := quoteDescription(b.Description) + b.raw.SetOption(descriptionKey, desc) + } + return b.raw } +// hack to trigger conditional quoting in the +// plumbing/format/config/Encoder.encodeOptions +// +// Current Encoder implementation uses Go %q format if value contains a backslash character, +// which is not consistent with reference git implementation. +// git just replaces newline characters with \n, while Encoder prints them directly. +// Until value quoting fix, we should escape description value by replacing newline characters with \n. +func quoteDescription(desc string) string { + return strings.ReplaceAll(desc, "\n", `\n`) +} + func (b *Branch) unmarshal(s *format.Subsection) error { b.raw = s @@ -85,6 +110,14 @@ func (b *Branch) unmarshal(s *format.Subsection) error { b.Remote = b.raw.Options.Get(remoteSection) b.Merge = plumbing.ReferenceName(b.raw.Options.Get(mergeKey)) b.Rebase = b.raw.Options.Get(rebaseKey) + b.Description = unquoteDescription(b.raw.Options.Get(descriptionKey)) return b.Validate() } + +// hack to enable conditional quoting in the +// plumbing/format/config/Encoder.encodeOptions +// goto quoteDescription for details. +func unquoteDescription(desc string) string { + return strings.ReplaceAll(desc, `\n`, "\n") +} diff --git a/config/config.go b/config/config.go index 1aee25a4c..a16a5e5f4 100644 --- a/config/config.go +++ b/config/config.go @@ -247,6 +247,7 @@ const ( rebaseKey = "rebase" nameKey = "name" emailKey = "email" + descriptionKey = "description" defaultBranchKey = "defaultBranch" // DefaultPackWindow holds the number of previous objects used to diff --git a/config/config_test.go b/config/config_test.go index 6f0242d96..91f7df2ae 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -50,6 +50,7 @@ func (s *ConfigSuite) TestUnmarshal(c *C) { [branch "master"] remote = origin merge = refs/heads/master + description = "Add support for branch description.\\n\\nEdit branch description: git branch --edit-description\\n" [init] defaultBranch = main [url "ssh://git@github.com/"] @@ -86,6 +87,7 @@ func (s *ConfigSuite) TestUnmarshal(c *C) { c.Assert(cfg.Submodules["qux"].Branch, Equals, "bar") c.Assert(cfg.Branches["master"].Remote, Equals, "origin") c.Assert(cfg.Branches["master"].Merge, Equals, plumbing.ReferenceName("refs/heads/master")) + c.Assert(cfg.Branches["master"].Description, Equals, "Add support for branch description.\n\nEdit branch description: git branch --edit-description\n") c.Assert(cfg.Init.DefaultBranch, Equals, "main") } @@ -111,6 +113,7 @@ func (s *ConfigSuite) TestMarshal(c *C) { [branch "master"] remote = origin merge = refs/heads/master + description = "Add support for branch description.\\n\\nEdit branch description: git branch --edit-description\\n" [url "ssh://git@github.com/"] insteadOf = https://github.com/ [init] @@ -149,9 +152,10 @@ func (s *ConfigSuite) TestMarshal(c *C) { } cfg.Branches["master"] = &Branch{ - Name: "master", - Remote: "origin", - Merge: "refs/heads/master", + Name: "master", + Remote: "origin", + Merge: "refs/heads/master", + Description: "Add support for branch description.\n\nEdit branch description: git branch --edit-description\n", } cfg.URLs["ssh://git@github.com/"] = &URL{ @@ -364,4 +368,5 @@ func (s *ConfigSuite) TestRemoveUrlOptions(c *C) { if strings.Contains(string(buf), "url") { c.Fatal("conifg should not contain any url sections") } + c.Assert(err, IsNil) }